| # Copyright (c) 2018 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Common code generator for command buffers.""" |
| |
| import itertools |
| import os.path |
| import re |
| import platform |
| from subprocess import call |
| |
| _SIZE_OF_UINT32 = 4 |
| _SIZE_OF_COMMAND_HEADER = 4 |
| _FIRST_SPECIFIC_COMMAND_ID = 256 |
| |
| _LICENSE = """// Copyright %s The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| """ |
| |
| _DO_NOT_EDIT_WARNING = """// This file is auto-generated from |
| // gpu/command_buffer/build_%s_cmd_buffer.py |
| // It's formatted by clang-format using chromium coding style: |
| // clang-format -i -style=chromium filename |
| // DO NOT EDIT! |
| |
| """ |
| |
| # This string is copied directly out of the gl2.h file from GLES2.0 |
| # |
| # Edits: |
| # |
| # *) Any argument that is a resourceID has been changed to GLid<Type>. |
| # (not pointer arguments) and if it's allowed to be zero it's GLidZero<Type> |
| # If it's allowed to not exist it's GLidBind<Type> |
| # |
| # *) All GLenums have been changed to GLenumTypeOfEnum |
| # |
| _GL_TYPES = { |
| 'GLenum': 'unsigned int', |
| 'GLboolean': 'unsigned char', |
| 'GLbitfield': 'unsigned int', |
| 'GLbyte': 'signed char', |
| 'GLshort': 'short', |
| 'GLint': 'int', |
| 'GLsizei': 'int', |
| 'GLubyte': 'unsigned char', |
| 'GLushort': 'unsigned short', |
| 'GLuint': 'unsigned int', |
| 'GLfloat': 'float', |
| 'GLclampf': 'float', |
| 'GLvoid': 'void', |
| 'GLfixed': 'int', |
| 'GLclampx': 'int' |
| } |
| |
| _GL_TYPES_32 = { |
| 'GLintptr': 'long int', |
| 'GLsizeiptr': 'long int' |
| } |
| |
| _GL_TYPES_64 = { |
| 'GLintptr': 'long long int', |
| 'GLsizeiptr': 'long long int' |
| } |
| |
| _ETC_COMPRESSED_TEXTURE_FORMATS = [ |
| 'GL_COMPRESSED_R11_EAC', |
| 'GL_COMPRESSED_SIGNED_R11_EAC', |
| 'GL_COMPRESSED_RG11_EAC', |
| 'GL_COMPRESSED_SIGNED_RG11_EAC', |
| 'GL_COMPRESSED_RGB8_ETC2', |
| 'GL_COMPRESSED_SRGB8_ETC2', |
| 'GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2', |
| 'GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2', |
| 'GL_COMPRESSED_RGBA8_ETC2_EAC', |
| 'GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC', |
| ] |
| |
| # This table specifies the different pepper interfaces that are supported for |
| # GL commands. 'dev' is true if it's a dev interface. |
| _PEPPER_INTERFACES = [ |
| {'name': '', 'dev': False}, |
| {'name': 'InstancedArrays', 'dev': False}, |
| {'name': 'FramebufferBlit', 'dev': False}, |
| {'name': 'FramebufferMultisample', 'dev': False}, |
| {'name': 'ChromiumEnableFeature', 'dev': False}, |
| {'name': 'ChromiumMapSub', 'dev': False}, |
| {'name': 'Query', 'dev': False}, |
| {'name': 'VertexArrayObject', 'dev': False}, |
| {'name': 'DrawBuffers', 'dev': True}, |
| ] |
| |
| |
| # Capabilities selected with glEnable |
| # on_change: string of C++ code that is executed when the state is changed. |
| _CAPABILITY_FLAGS = [ |
| {'name': 'blend'}, |
| {'name': 'cull_face'}, |
| {'name': 'depth_test', |
| 'on_change': 'framebuffer_state_.clear_state_dirty = true;'}, |
| {'name': 'dither', 'default': True}, |
| {'name': 'framebuffer_srgb_ext', 'default': True, 'no_init': True, |
| 'extension_flag': 'ext_srgb_write_control'}, |
| {'name': 'polygon_offset_fill'}, |
| {'name': 'sample_alpha_to_coverage'}, |
| {'name': 'sample_coverage'}, |
| {'name': 'scissor_test'}, |
| {'name': 'stencil_test', |
| 'on_change': '''state_.stencil_state_changed_since_validation = true; |
| framebuffer_state_.clear_state_dirty = true;'''}, |
| {'name': 'rasterizer_discard', 'es3': True}, |
| {'name': 'primitive_restart_fixed_index', 'es3': True}, |
| {'name': 'multisample_ext', 'default': True, |
| 'extension_flag': 'ext_multisample_compatibility'}, |
| {'name': 'sample_alpha_to_one_ext', |
| 'extension_flag': 'ext_multisample_compatibility'}, |
| ] |
| |
| _STATE_INFO = { |
| 'ClearColor': { |
| 'type': 'Normal', |
| 'func': 'ClearColor', |
| 'enum': 'GL_COLOR_CLEAR_VALUE', |
| 'states': [ |
| {'name': 'color_clear_red', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'color_clear_green', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'color_clear_blue', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'color_clear_alpha', 'type': 'GLfloat', 'default': '0.0f'}, |
| ], |
| }, |
| 'ClearDepthf': { |
| 'type': 'Normal', |
| 'func': 'ClearDepth', |
| 'enum': 'GL_DEPTH_CLEAR_VALUE', |
| 'states': [ |
| {'name': 'depth_clear', 'type': 'GLclampf', 'default': '1.0f'}, |
| ], |
| }, |
| 'ColorMask': { |
| 'type': 'Normal', |
| 'func': 'ColorMask', |
| 'enum': 'GL_COLOR_WRITEMASK', |
| 'states': [ |
| { |
| 'name': 'color_mask_red', |
| 'type': 'GLboolean', |
| 'default': 'true', |
| 'cached': True |
| }, |
| { |
| 'name': 'color_mask_green', |
| 'type': 'GLboolean', |
| 'default': 'true', |
| 'cached': True |
| }, |
| { |
| 'name': 'color_mask_blue', |
| 'type': 'GLboolean', |
| 'default': 'true', |
| 'cached': True |
| }, |
| { |
| 'name': 'color_mask_alpha', |
| 'type': 'GLboolean', |
| 'default': 'true', |
| 'cached': True |
| }, |
| ], |
| 'on_change': 'framebuffer_state_.clear_state_dirty = true;', |
| }, |
| 'ClearStencil': { |
| 'type': 'Normal', |
| 'func': 'ClearStencil', |
| 'enum': 'GL_STENCIL_CLEAR_VALUE', |
| 'states': [ |
| {'name': 'stencil_clear', 'type': 'GLint', 'default': '0'}, |
| ], |
| }, |
| 'CoverageModulationCHROMIUM': { |
| 'type': 'Normal', |
| 'func': 'CoverageModulationNV', |
| 'extension_flag': 'chromium_framebuffer_mixed_samples', |
| 'states': [ |
| { 'enum': 'GL_COVERAGE_MODULATION_CHROMIUM', |
| 'name': 'coverage_modulation', |
| 'type': 'GLenum', |
| 'default': 'GL_NONE', |
| }, |
| ] |
| }, |
| 'BlendColor': { |
| 'type': 'Normal', |
| 'func': 'BlendColor', |
| 'enum': 'GL_BLEND_COLOR', |
| 'states': [ |
| {'name': 'blend_color_red', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'blend_color_green', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'blend_color_blue', 'type': 'GLfloat', 'default': '0.0f'}, |
| {'name': 'blend_color_alpha', 'type': 'GLfloat', 'default': '0.0f'}, |
| ], |
| }, |
| 'BlendEquation': { |
| 'type': 'SrcDst', |
| 'func': 'BlendEquationSeparate', |
| 'states': [ |
| { |
| 'name': 'blend_equation_rgb', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_EQUATION_RGB', |
| 'default': 'GL_FUNC_ADD', |
| }, |
| { |
| 'name': 'blend_equation_alpha', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_EQUATION_ALPHA', |
| 'default': 'GL_FUNC_ADD', |
| }, |
| ], |
| }, |
| 'BlendFunc': { |
| 'type': 'SrcDst', |
| 'func': 'BlendFuncSeparate', |
| 'states': [ |
| { |
| 'name': 'blend_source_rgb', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_SRC_RGB', |
| 'default': 'GL_ONE', |
| }, |
| { |
| 'name': 'blend_dest_rgb', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_DST_RGB', |
| 'default': 'GL_ZERO', |
| }, |
| { |
| 'name': 'blend_source_alpha', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_SRC_ALPHA', |
| 'default': 'GL_ONE', |
| }, |
| { |
| 'name': 'blend_dest_alpha', |
| 'type': 'GLenum', |
| 'enum': 'GL_BLEND_DST_ALPHA', |
| 'default': 'GL_ZERO', |
| }, |
| ], |
| }, |
| 'PolygonOffset': { |
| 'type': 'Normal', |
| 'func': 'PolygonOffset', |
| 'states': [ |
| { |
| 'name': 'polygon_offset_factor', |
| 'type': 'GLfloat', |
| 'enum': 'GL_POLYGON_OFFSET_FACTOR', |
| 'default': '0.0f', |
| }, |
| { |
| 'name': 'polygon_offset_units', |
| 'type': 'GLfloat', |
| 'enum': 'GL_POLYGON_OFFSET_UNITS', |
| 'default': '0.0f', |
| }, |
| ], |
| }, |
| 'CullFace': { |
| 'type': 'Normal', |
| 'func': 'CullFace', |
| 'enum': 'GL_CULL_FACE_MODE', |
| 'states': [ |
| { |
| 'name': 'cull_mode', |
| 'type': 'GLenum', |
| 'default': 'GL_BACK', |
| }, |
| ], |
| }, |
| 'FrontFace': { |
| 'type': 'Normal', |
| 'func': 'FrontFace', |
| 'enum': 'GL_FRONT_FACE', |
| 'states': [{'name': 'front_face', 'type': 'GLenum', 'default': 'GL_CCW'}], |
| }, |
| 'DepthFunc': { |
| 'type': 'Normal', |
| 'func': 'DepthFunc', |
| 'enum': 'GL_DEPTH_FUNC', |
| 'states': [{'name': 'depth_func', 'type': 'GLenum', 'default': 'GL_LESS'}], |
| }, |
| 'DepthRange': { |
| 'type': 'Normal', |
| 'func': 'DepthRange', |
| 'enum': 'GL_DEPTH_RANGE', |
| 'states': [ |
| {'name': 'z_near', 'type': 'GLclampf', 'default': '0.0f'}, |
| {'name': 'z_far', 'type': 'GLclampf', 'default': '1.0f'}, |
| ], |
| }, |
| 'SampleCoverage': { |
| 'type': 'Normal', |
| 'func': 'SampleCoverage', |
| 'states': [ |
| { |
| 'name': 'sample_coverage_value', |
| 'type': 'GLclampf', |
| 'enum': 'GL_SAMPLE_COVERAGE_VALUE', |
| 'default': '1.0f', |
| }, |
| { |
| 'name': 'sample_coverage_invert', |
| 'type': 'GLboolean', |
| 'enum': 'GL_SAMPLE_COVERAGE_INVERT', |
| 'default': 'false', |
| }, |
| ], |
| }, |
| 'StencilMask': { |
| 'type': 'FrontBack', |
| 'func': 'StencilMaskSeparate', |
| 'states': [ |
| { |
| 'name': 'stencil_front_writemask', |
| 'type': 'GLuint', |
| 'enum': 'GL_STENCIL_WRITEMASK', |
| 'default': '0xFFFFFFFFU', |
| 'cached': True, |
| }, |
| { |
| 'name': 'stencil_back_writemask', |
| 'type': 'GLuint', |
| 'enum': 'GL_STENCIL_BACK_WRITEMASK', |
| 'default': '0xFFFFFFFFU', |
| 'cached': True, |
| }, |
| ], |
| 'on_change': '''framebuffer_state_.clear_state_dirty = true; |
| state_.stencil_state_changed_since_validation = true;''', |
| }, |
| 'StencilOp': { |
| 'type': 'FrontBack', |
| 'func': 'StencilOpSeparate', |
| 'states': [ |
| { |
| 'name': 'stencil_front_fail_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_FAIL', |
| 'default': 'GL_KEEP', |
| }, |
| { |
| 'name': 'stencil_front_z_fail_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_PASS_DEPTH_FAIL', |
| 'default': 'GL_KEEP', |
| }, |
| { |
| 'name': 'stencil_front_z_pass_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_PASS_DEPTH_PASS', |
| 'default': 'GL_KEEP', |
| }, |
| { |
| 'name': 'stencil_back_fail_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_BACK_FAIL', |
| 'default': 'GL_KEEP', |
| }, |
| { |
| 'name': 'stencil_back_z_fail_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_BACK_PASS_DEPTH_FAIL', |
| 'default': 'GL_KEEP', |
| }, |
| { |
| 'name': 'stencil_back_z_pass_op', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_BACK_PASS_DEPTH_PASS', |
| 'default': 'GL_KEEP', |
| }, |
| ], |
| }, |
| 'StencilFunc': { |
| 'type': 'FrontBack', |
| 'func': 'StencilFuncSeparate', |
| 'states': [ |
| { |
| 'name': 'stencil_front_func', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_FUNC', |
| 'default': 'GL_ALWAYS', |
| }, |
| { |
| 'name': 'stencil_front_ref', |
| 'type': 'GLint', |
| 'enum': 'GL_STENCIL_REF', |
| 'default': '0', |
| }, |
| { |
| 'name': 'stencil_front_mask', |
| 'type': 'GLuint', |
| 'enum': 'GL_STENCIL_VALUE_MASK', |
| 'default': '0xFFFFFFFFU', |
| }, |
| { |
| 'name': 'stencil_back_func', |
| 'type': 'GLenum', |
| 'enum': 'GL_STENCIL_BACK_FUNC', |
| 'default': 'GL_ALWAYS', |
| }, |
| { |
| 'name': 'stencil_back_ref', |
| 'type': 'GLint', |
| 'enum': 'GL_STENCIL_BACK_REF', |
| 'default': '0', |
| }, |
| { |
| 'name': 'stencil_back_mask', |
| 'type': 'GLuint', |
| 'enum': 'GL_STENCIL_BACK_VALUE_MASK', |
| 'default': '0xFFFFFFFFU', |
| }, |
| ], |
| 'on_change': 'state_.stencil_state_changed_since_validation = true;', |
| }, |
| 'Hint': { |
| 'type': 'NamedParameter', |
| 'func': 'Hint', |
| 'states': [ |
| { |
| 'name': 'hint_generate_mipmap', |
| 'type': 'GLenum', |
| 'enum': 'GL_GENERATE_MIPMAP_HINT', |
| 'default': 'GL_DONT_CARE', |
| 'gl_version_flag': '!is_desktop_core_profile' |
| }, |
| { |
| 'name': 'hint_fragment_shader_derivative', |
| 'type': 'GLenum', |
| 'enum': 'GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES', |
| 'default': 'GL_DONT_CARE', |
| 'extension_flag': 'oes_standard_derivatives' |
| }, |
| { |
| 'name': 'hint_texture_filtering', |
| 'type': 'GLenum', |
| 'enum': 'GL_TEXTURE_FILTERING_HINT_CHROMIUM', |
| 'default': 'GL_NICEST', |
| 'extension_flag': 'chromium_texture_filtering_hint' |
| } |
| ], |
| }, |
| 'PixelStore': { |
| 'type': 'NamedParameter', |
| 'func': 'PixelStorei', |
| 'states': [ |
| { |
| 'name': 'pack_alignment', |
| 'type': 'GLint', |
| 'enum': 'GL_PACK_ALIGNMENT', |
| 'default': '4' |
| }, |
| { |
| 'name': 'unpack_alignment', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_ALIGNMENT', |
| 'default': '4' |
| }, |
| { |
| 'name': 'pack_row_length', |
| 'type': 'GLint', |
| 'enum': 'GL_PACK_ROW_LENGTH', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'pack_skip_pixels', |
| 'type': 'GLint', |
| 'enum': 'GL_PACK_SKIP_PIXELS', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'pack_skip_rows', |
| 'type': 'GLint', |
| 'enum': 'GL_PACK_SKIP_ROWS', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'unpack_row_length', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_ROW_LENGTH', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'unpack_image_height', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_IMAGE_HEIGHT', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'unpack_skip_pixels', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_SKIP_PIXELS', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'unpack_skip_rows', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_SKIP_ROWS', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| }, |
| { |
| 'name': 'unpack_skip_images', |
| 'type': 'GLint', |
| 'enum': 'GL_UNPACK_SKIP_IMAGES', |
| 'default': '0', |
| 'es3': True, |
| 'manual': True, |
| } |
| ], |
| }, |
| # TODO: Consider implemenenting these states |
| # GL_ACTIVE_TEXTURE |
| 'LineWidth': { |
| 'type': 'Normal', |
| 'custom_function' : True, |
| 'func': 'DoLineWidth', |
| 'enum': 'GL_LINE_WIDTH', |
| 'states': [ |
| { |
| 'name': 'line_width', |
| 'type': 'GLfloat', |
| 'default': '1.0f', |
| 'range_checks': [{'check': "<= 0.0f", 'test_value': "0.0f"}], |
| 'nan_check': True, |
| }], |
| }, |
| 'DepthMask': { |
| 'type': 'Normal', |
| 'func': 'DepthMask', |
| 'enum': 'GL_DEPTH_WRITEMASK', |
| 'states': [ |
| { |
| 'name': 'depth_mask', |
| 'type': 'GLboolean', |
| 'default': 'true', |
| 'cached': True |
| }, |
| ], |
| 'on_change': 'framebuffer_state_.clear_state_dirty = true;', |
| }, |
| 'Scissor': { |
| 'type': 'Normal', |
| 'func': 'Scissor', |
| 'enum': 'GL_SCISSOR_BOX', |
| 'states': [ |
| # NOTE: These defaults reset at GLES2DecoderImpl::Initialization. |
| { |
| 'name': 'scissor_x', |
| 'type': 'GLint', |
| 'default': '0', |
| 'expected': 'kViewportX', |
| }, |
| { |
| 'name': 'scissor_y', |
| 'type': 'GLint', |
| 'default': '0', |
| 'expected': 'kViewportY', |
| }, |
| { |
| 'name': 'scissor_width', |
| 'type': 'GLsizei', |
| 'default': '1', |
| 'expected': 'kViewportWidth', |
| }, |
| { |
| 'name': 'scissor_height', |
| 'type': 'GLsizei', |
| 'default': '1', |
| 'expected': 'kViewportHeight', |
| }, |
| ], |
| }, |
| 'Viewport': { |
| 'type': 'Normal', |
| 'func': 'Viewport', |
| 'enum': 'GL_VIEWPORT', |
| 'states': [ |
| # NOTE: These defaults reset at GLES2DecoderImpl::Initialization. |
| { |
| 'name': 'viewport_x', |
| 'type': 'GLint', |
| 'default': '0', |
| 'expected': 'kViewportX', |
| }, |
| { |
| 'name': 'viewport_y', |
| 'type': 'GLint', |
| 'default': '0', |
| 'expected': 'kViewportY', |
| }, |
| { |
| 'name': 'viewport_width', |
| 'type': 'GLsizei', |
| 'default': '1', |
| 'expected': 'kViewportWidth', |
| }, |
| { |
| 'name': 'viewport_height', |
| 'type': 'GLsizei', |
| 'default': '1', |
| 'expected': 'kViewportHeight', |
| }, |
| ], |
| }, |
| 'MatrixValuesCHROMIUM': { |
| 'type': 'NamedParameter', |
| 'func': 'MatrixLoadfEXT', |
| 'states': [ |
| { 'enum': 'GL_PATH_MODELVIEW_MATRIX_CHROMIUM', |
| 'enum_set': 'GL_PATH_MODELVIEW_CHROMIUM', |
| 'name': 'modelview_matrix', |
| 'type': 'GLfloat', |
| 'default': [ |
| '1.0f', '0.0f','0.0f','0.0f', |
| '0.0f', '1.0f','0.0f','0.0f', |
| '0.0f', '0.0f','1.0f','0.0f', |
| '0.0f', '0.0f','0.0f','1.0f', |
| ], |
| 'extension_flag': 'chromium_path_rendering', |
| }, |
| { 'enum': 'GL_PATH_PROJECTION_MATRIX_CHROMIUM', |
| 'enum_set': 'GL_PATH_PROJECTION_CHROMIUM', |
| 'name': 'projection_matrix', |
| 'type': 'GLfloat', |
| 'default': [ |
| '1.0f', '0.0f','0.0f','0.0f', |
| '0.0f', '1.0f','0.0f','0.0f', |
| '0.0f', '0.0f','1.0f','0.0f', |
| '0.0f', '0.0f','0.0f','1.0f', |
| ], |
| 'extension_flag': 'chromium_path_rendering', |
| }, |
| ], |
| }, |
| 'PathStencilFuncCHROMIUM': { |
| 'type': 'Normal', |
| 'func': 'PathStencilFuncNV', |
| 'extension_flag': 'chromium_path_rendering', |
| 'states': [ |
| { |
| 'name': 'stencil_path_func', |
| 'type': 'GLenum', |
| 'enum': 'GL_PATH_STENCIL_FUNC_CHROMIUM', |
| 'default': 'GL_ALWAYS', |
| }, |
| { |
| 'name': 'stencil_path_ref', |
| 'type': 'GLint', |
| 'enum': 'GL_PATH_STENCIL_REF_CHROMIUM', |
| 'default': '0', |
| }, |
| { |
| 'name': 'stencil_path_mask', |
| 'type': 'GLuint', |
| 'enum': 'GL_PATH_STENCIL_VALUE_MASK_CHROMIUM', |
| 'default': '0xFFFFFFFFU', |
| }, |
| ], |
| }, |
| 'WindowRectanglesEXT': { |
| 'type': 'Normal', |
| 'func': 'WindowRectanglesEXT', |
| 'custom_function': True, |
| 'extension_flag': 'ext_window_rectangles', |
| 'no_init': True, |
| 'states': [ |
| { |
| 'name': 'window_rectangles_mode', |
| 'type': 'GLenum', |
| 'enum': 'GL_WINDOW_RECTANGLE_MODE_EXT', |
| 'default': 'GL_EXCLUSIVE_EXT', |
| }, |
| { |
| 'name': 'num_window_rectangles', |
| 'type': 'GLint', |
| 'enum': 'GL_NUM_WINDOW_RECTANGLES_EXT', |
| 'default': '0', |
| }, |
| ], |
| }, |
| } |
| |
| _prefix = None |
| _upper_prefix = None |
| _lower_prefix = None |
| def InitializePrefix(mixed_case_prefix): |
| """Initialize prefix used for autogenerated code. |
| |
| Must be called before autogenerating code. Prefixes are used by autogenerated |
| code in many places: class names, filenames, namespaces, constants, |
| defines. Given a single mixed case prefix suitable for a class name, we also |
| initialize lower and upper case prefixes for other uses (e.g. filenames and |
| #defines). |
| """ |
| global _prefix |
| if _prefix: |
| raise AssertionError |
| _prefix = mixed_case_prefix |
| |
| global _upper_prefix |
| _upper_prefix = mixed_case_prefix.upper() |
| |
| global _lower_prefix |
| _lower_prefix = mixed_case_prefix.lower() |
| |
| |
| def _Namespace(): |
| if _lower_prefix != 'gles2': |
| return 'gles2::' |
| return '' |
| |
| |
| def Grouper(n, iterable, fillvalue=None): |
| """Collect data into fixed-length chunks or blocks""" |
| args = [iter(iterable)] * n |
| return itertools.izip_longest(fillvalue=fillvalue, *args) |
| |
| |
| def SplitWords(input_string): |
| """Split by '_' if found, otherwise split at uppercase/numeric chars. |
| |
| Will split "some_TEXT" into ["some", "TEXT"], "CamelCase" into ["Camel", |
| "Case"], and "Vector3" into ["Vector", "3"]. |
| """ |
| if input_string.find('_') > -1: |
| # 'some_TEXT_' -> 'some TEXT' |
| return input_string.replace('_', ' ').strip().split() |
| else: |
| input_string = input_string.replace('::', ' ') |
| if re.search('[A-Z]', input_string) and re.search('[a-z]', input_string): |
| # mixed case. |
| # look for capitalization to cut input_strings |
| # 'SomeText' -> 'Some Text' |
| input_string = re.sub('([A-Z])', r' \1', input_string).strip() |
| # 'Vector3' -> 'Vector 3' |
| input_string = re.sub('([^0-9])([0-9])', r'\1 \2', input_string) |
| return input_string.split() |
| |
| def ToUnderscore(input_string): |
| """converts CamelCase to camel_case.""" |
| words = SplitWords(input_string) |
| return '_'.join([word.lower() for word in words]) |
| |
| def ValidatorClassName(type_name): |
| """Converts some::namespace::TypeName to SomeNamespaceTypeNameValidator.""" |
| words = SplitWords(type_name) |
| prefix = ''.join([word.title() for word in words]) |
| return '%sValidator' % prefix |
| |
| def CachedStateName(item): |
| if item.get('cached', False): |
| return 'cached_' + item['name'] |
| return item['name'] |
| |
| def GuardState(state, operation): |
| if 'manual' in state: |
| assert state['manual'] |
| return "" |
| |
| result = [] |
| result_end = [] |
| if 'es3' in state: |
| assert state['es3'] |
| result.append(" if (feature_info_->IsES3Capable()) {\n"); |
| result_end.append(" }\n") |
| if 'extension_flag' in state: |
| result.append(" if (feature_info_->feature_flags().%s) {\n " % |
| (state['extension_flag'])) |
| result_end.append(" }\n") |
| if 'gl_version_flag' in state: |
| name = state['gl_version_flag'] |
| inverted = '' |
| if name[0] == '!': |
| inverted = '!' |
| name = name[1:] |
| result.append(" if (%sfeature_info_->gl_version_info().%s) {\n" % |
| (inverted, name)) |
| result_end.append(" }\n") |
| |
| result.append(operation) |
| return ''.join(result + result_end) |
| |
| def ToGLExtensionString(extension_flag): |
| """Returns GL-type extension string of a extension flag.""" |
| if extension_flag == "oes_compressed_etc1_rgb8_texture": |
| return "OES_compressed_ETC1_RGB8_texture" # Fixup inconsitency with rgb8, |
| # unfortunate. |
| uppercase_words = [ 'img', 'ext', 'arb', 'chromium', 'oes', 'amd', 'bgra8888', |
| 'egl', 'atc', 'etc1', 'angle'] |
| parts = extension_flag.split('_') |
| return "_".join( |
| [part.upper() if part in uppercase_words else part for part in parts]) |
| |
| def ToCamelCase(input_string): |
| """converts ABC_underscore_case to ABCUnderscoreCase.""" |
| return ''.join(w[0].upper() + w[1:] for w in input_string.split('_')) |
| |
| def EnumsConflict(a, b): |
| """Returns true if the enums have different names (ignoring suffixes) and one |
| of them is a Chromium enum.""" |
| if a == b: |
| return False |
| |
| if b.endswith('_CHROMIUM'): |
| a, b = b, a |
| |
| if not a.endswith('_CHROMIUM'): |
| return False |
| |
| def removesuffix(string, suffix): |
| if not string.endswith(suffix): |
| return string |
| return string[:-len(suffix)] |
| b = removesuffix(b, "_NV") |
| b = removesuffix(b, "_EXT") |
| b = removesuffix(b, "_OES") |
| return removesuffix(a, "_CHROMIUM") != b |
| |
| def GetGLGetTypeConversion(result_type, value_type, value): |
| """Makes a gl compatible type conversion string for accessing state variables. |
| |
| Useful when accessing state variables through glGetXXX calls. |
| glGet documetation (for example, the manual pages): |
| [...] If glGetIntegerv is called, [...] most floating-point values are |
| rounded to the nearest integer value. [...] |
| |
| Args: |
| result_type: the gl type to be obtained |
| value_type: the GL type of the state variable |
| value: the name of the state variable |
| |
| Returns: |
| String that converts the state variable to desired GL type according to GL |
| rules. |
| """ |
| |
| if result_type == 'GLint': |
| if value_type == 'GLfloat': |
| return 'static_cast<GLint>(round(%s))' % value |
| return 'static_cast<%s>(%s)' % (result_type, value) |
| |
| |
| class CWriter(object): |
| """Context manager that creates a C source file. |
| |
| To be used with the `with` statement. Returns a normal `file` type, open only |
| for writing - any existing files with that name will be overwritten. It will |
| automatically write the contents of `_LICENSE` and `_DO_NOT_EDIT_WARNING` |
| at the beginning. |
| |
| Example: |
| with CWriter("file.cpp") as myfile: |
| myfile.write("hello") |
| # type(myfile) == file |
| """ |
| def __init__(self, filename, year): |
| self.filename = filename |
| self._file = open(filename, 'wb') |
| self._ENTER_MSG = _LICENSE % year + _DO_NOT_EDIT_WARNING % _lower_prefix |
| self._EXIT_MSG = "" |
| |
| def __enter__(self): |
| self._file.write(self._ENTER_MSG) |
| return self._file |
| |
| def __exit__(self, exc_type, exc_value, traceback): |
| self._file.write(self._EXIT_MSG) |
| self._file.close() |
| |
| |
| class CHeaderWriter(CWriter): |
| """Context manager that creates a C header file. |
| |
| Works the same way as CWriter, except it will also add the #ifdef guard |
| around it. If `file_comment` is set, it will write that before the #ifdef |
| guard. |
| """ |
| def __init__(self, filename, year, file_comment=None): |
| super(CHeaderWriter, self).__init__(filename, year) |
| guard = self._get_guard() |
| if file_comment is None: |
| file_comment = "" |
| self._ENTER_MSG = self._ENTER_MSG + file_comment \ |
| + "#ifndef %s\n#define %s\n\n" % (guard, guard) |
| self._EXIT_MSG = self._EXIT_MSG + "#endif // %s\n" % guard |
| |
| def _get_guard(self): |
| non_alnum_re = re.compile(r'[^a-zA-Z0-9]') |
| base = os.path.abspath(self.filename) |
| while os.path.basename(base) != 'src': |
| new_base = os.path.dirname(base) |
| assert new_base != base # Prevent infinite loop. |
| base = new_base |
| hpath = os.path.relpath(self.filename, base) |
| return non_alnum_re.sub('_', hpath).upper() + '_' |
| |
| |
| class TypeHandler(object): |
| """This class emits code for a particular type of function.""" |
| |
| _remove_expected_call_re = re.compile(r' EXPECT_CALL.*?;\n', re.S) |
| |
| def InitFunction(self, func): |
| """Add or adjust anything type specific for this function.""" |
| if func.GetInfo('needs_size') and not func.name.endswith('Bucket'): |
| func.AddCmdArg(DataSizeArgument('data_size')) |
| |
| def NeedsDataTransferFunction(self, func): |
| """Overriden from TypeHandler.""" |
| return func.num_pointer_args >= 1 |
| |
| def WriteStruct(self, func, f): |
| """Writes a structure that matches the arguments to a function.""" |
| comment = func.GetInfo('cmd_comment') |
| if not comment == None: |
| f.write(comment) |
| f.write("struct %s {\n" % func.name) |
| f.write(" typedef %s ValueType;\n" % func.name) |
| f.write(" static const CommandId kCmdId = k%s;\n" % func.name) |
| func.WriteCmdArgFlag(f) |
| func.WriteCmdFlag(f) |
| f.write("\n") |
| result = func.GetInfo('result') |
| if not result == None: |
| if len(result) == 1: |
| f.write(" typedef %s Result;\n\n" % result[0]) |
| else: |
| f.write(" struct Result {\n") |
| for line in result: |
| f.write(" %s;\n" % line) |
| f.write(" };\n\n") |
| |
| func.WriteCmdComputeSize(f) |
| func.WriteCmdSetHeader(f) |
| func.WriteCmdInit(f) |
| func.WriteCmdSet(f) |
| func.WriteArgAccessors(f) |
| |
| f.write(" gpu::CommandHeader header;\n") |
| total_args = 0 |
| args = func.GetCmdArgs() |
| for arg in args: |
| for cmd_type, name in arg.GetArgDecls(): |
| f.write(" %s %s;\n" % (cmd_type, name)) |
| total_args += 1 |
| trace_queue = func.GetInfo('trace_queueing_flow', False) |
| if trace_queue: |
| f.write(" uint32_t trace_id;\n") |
| total_args += 1 |
| |
| consts = func.GetCmdConstants() |
| for const in consts: |
| const_decls = const.GetArgDecls() |
| assert(len(const_decls) == 1) |
| const_cmd_type, const_name = const_decls[0] |
| f.write(" static const %s %s = %s;\n" % |
| (const_cmd_type, const_name, const.GetConstantValue())) |
| |
| f.write("};\n") |
| f.write("\n") |
| |
| size = total_args * _SIZE_OF_UINT32 + _SIZE_OF_COMMAND_HEADER |
| f.write("static_assert(sizeof(%s) == %d,\n" % (func.name, size)) |
| f.write(" \"size of %s should be %d\");\n" % |
| (func.name, size)) |
| f.write("static_assert(offsetof(%s, header) == 0,\n" % func.name) |
| f.write(" \"offset of %s header should be 0\");\n" % |
| func.name) |
| offset = _SIZE_OF_COMMAND_HEADER |
| for arg in args: |
| for _, name in arg.GetArgDecls(): |
| f.write("static_assert(offsetof(%s, %s) == %d,\n" % |
| (func.name, name, offset)) |
| f.write(" \"offset of %s %s should be %d\");\n" % |
| (func.name, name, offset)) |
| offset += _SIZE_OF_UINT32 |
| if not result == None and len(result) > 1: |
| offset = 0; |
| for line in result: |
| parts = line.split() |
| name = parts[-1] |
| check = """ |
| static_assert(offsetof(%(cmd_name)s::Result, %(field_name)s) == %(offset)d, |
| "offset of %(cmd_name)s Result %(field_name)s should be " |
| "%(offset)d"); |
| """ |
| f.write((check.strip() + "\n") % { |
| 'cmd_name': func.name, |
| 'field_name': name, |
| 'offset': offset, |
| }) |
| offset += _SIZE_OF_UINT32 |
| f.write("\n") |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Writes the handler implementation for this command.""" |
| args = [] |
| for arg in func.GetOriginalArgs(): |
| if arg.name.endswith("size") and arg.type == "GLsizei": |
| args.append("num_%s" % func.GetLastOriginalArg().name) |
| elif arg.name == "length": |
| args.append("nullptr") |
| else: |
| args.append(arg.name) |
| |
| if func.GetInfo('type') == 'GETn' and func.name != 'GetSynciv': |
| args.append('num_values') |
| |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), ", ".join(args))) |
| |
| def WriteCmdSizeTest(self, _func, f): |
| """Writes the size test for a command.""" |
| f.write(" EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);\n") |
| |
| def WriteFormatTest(self, func, f): |
| """Writes a format test for a command.""" |
| f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name)) |
| f.write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" % |
| (func.name, func.name)) |
| f.write(" void* next_cmd = cmd.Set(\n") |
| f.write(" &cmd") |
| args = func.GetCmdArgs() |
| for value, arg in enumerate(args): |
| f.write(",\n static_cast<%s>(%d)" % (arg.type, value + 11)) |
| f.write(");\n") |
| f.write(" EXPECT_EQ(static_cast<uint32_t>(cmds::%s::kCmdId),\n" % |
| func.name) |
| f.write(" cmd.header.command);\n") |
| func.type_handler.WriteCmdSizeTest(func, f) |
| for value, arg in enumerate(args): |
| f.write(" EXPECT_EQ(static_cast<%s>(%d), %s);\n" % |
| (arg.type, value + 11, arg.GetArgAccessor('cmd'))) |
| f.write(" CheckBytesWrittenMatchesExpectedSize(\n") |
| f.write(" next_cmd, sizeof(cmd));\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteImmediateFormatTest(self, func, f): |
| """Writes a format test for an immediate version of a command.""" |
| pass |
| |
| def WriteGetDataSizeCode(self, func, arg, f): |
| """Writes the code to set data_size used in validation""" |
| pass |
| |
| def WriteImmediateHandlerImplementation (self, func, f): |
| """Writes the handler impl for the immediate version of a command.""" |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| |
| def WriteBucketHandlerImplementation (self, func, f): |
| """Writes the handler impl for the bucket version of a command.""" |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| |
| def WriteServiceHandlerFunctionHeader(self, func, f): |
| """Writes function header for service implementation handlers.""" |
| f.write("""error::Error %(prefix)sDecoderImpl::Handle%(name)s( |
| uint32_t immediate_data_size, const volatile void* cmd_data) { |
| """ % {'name': func.name, 'prefix' : _prefix}) |
| if func.IsES3(): |
| f.write("""if (!feature_info_->IsWebGL2OrES3OrHigherContext()) |
| return error::kUnknownCommand; |
| """) |
| if func.IsES31(): |
| f.write("""return error::kUnknownCommand; |
| } |
| |
| """) |
| return |
| if func.GetCmdArgs(): |
| f.write("""const volatile %(prefix)s::cmds::%(name)s& c = |
| *static_cast<const volatile %(prefix)s::cmds::%(name)s*>(cmd_data); |
| """ % {'name': func.name, 'prefix': _lower_prefix}) |
| |
| def WriteServiceHandlerArgGetCode(self, func, f): |
| """Writes the argument unpack code for service handlers.""" |
| if len(func.GetOriginalArgs()) > 0: |
| for arg in func.GetOriginalArgs(): |
| if not arg.IsPointer(): |
| arg.WriteGetCode(f) |
| |
| # Write pointer arguments second. Sizes may be dependent on other args |
| for arg in func.GetOriginalArgs(): |
| if arg.IsPointer(): |
| self.WriteGetDataSizeCode(func, arg, f) |
| arg.WriteGetCode(f) |
| |
| def WriteImmediateServiceHandlerArgGetCode(self, func, f): |
| """Writes the argument unpack code for immediate service handlers.""" |
| for arg in func.GetOriginalArgs(): |
| if arg.IsPointer(): |
| self.WriteGetDataSizeCode(func, arg, f) |
| arg.WriteGetCode(f) |
| |
| def WriteBucketServiceHandlerArgGetCode(self, func, f): |
| """Writes the argument unpack code for bucket service handlers.""" |
| for arg in func.GetCmdArgs(): |
| arg.WriteGetCode(f) |
| for arg in func.GetOriginalArgs(): |
| if arg.IsConstant(): |
| arg.WriteGetCode(f) |
| self.WriteGetDataSizeCode(func, arg, f) |
| |
| def WriteServiceImplementation(self, func, f): |
| """Writes the service implementation for a command.""" |
| self.WriteServiceHandlerFunctionHeader(func, f) |
| if func.IsES31(): |
| return |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteHandlerDeferReadWrite(func, f); |
| self.WriteServiceHandlerArgGetCode(func, f) |
| func.WriteHandlerValidation(f) |
| func.WriteQueueTraceEvent(f) |
| func.WriteHandlerImplementation(f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteImmediateServiceImplementation(self, func, f): |
| """Writes the service implementation for an immediate version of command.""" |
| self.WriteServiceHandlerFunctionHeader(func, f) |
| if func.IsES31(): |
| return |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteHandlerDeferReadWrite(func, f); |
| self.WriteImmediateServiceHandlerArgGetCode(func, f) |
| func.WriteHandlerValidation(f) |
| func.WriteQueueTraceEvent(f) |
| func.WriteHandlerImplementation(f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteBucketServiceImplementation(self, func, f): |
| """Writes the service implementation for a bucket version of command.""" |
| self.WriteServiceHandlerFunctionHeader(func, f) |
| if func.IsES31(): |
| return |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteHandlerDeferReadWrite(func, f); |
| self.WriteBucketServiceHandlerArgGetCode(func, f) |
| func.WriteHandlerValidation(f) |
| func.WriteQueueTraceEvent(f) |
| func.WriteHandlerImplementation(f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WritePassthroughServiceFunctionHeader(self, func, f): |
| """Writes function header for service passthrough handlers.""" |
| f.write("""error::Error GLES2DecoderPassthroughImpl::Handle%(name)s( |
| uint32_t immediate_data_size, const volatile void* cmd_data) { |
| """ % {'name': func.name}) |
| if func.IsES3(): |
| f.write("""if (!feature_info_->IsWebGL2OrES3OrHigherContext()) |
| return error::kUnknownCommand; |
| """) |
| if func.IsES31(): |
| f.write("""if (!feature_info_->IsWebGL2ComputeContext()) |
| return error::kUnknownCommand; |
| """) |
| if func.GetCmdArgs(): |
| f.write("""const volatile gles2::cmds::%(name)s& c = |
| *static_cast<const volatile gles2::cmds::%(name)s*>(cmd_data); |
| """ % {'name': func.name}) |
| |
| def WritePassthroughServiceFunctionDoerCall(self, func, f): |
| """Writes the function call to the passthrough service doer.""" |
| f.write(""" error::Error error = Do%(name)s(%(args)s); |
| if (error != error::kNoError) { |
| return error; |
| }""" % {'name': func.original_name, |
| 'args': func.MakePassthroughServiceDoerArgString("")}) |
| |
| def WritePassthroughServiceImplementation(self, func, f): |
| """Writes the service implementation for a command.""" |
| self.WritePassthroughServiceFunctionHeader(func, f) |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteServiceHandlerArgGetCode(func, f) |
| func.WritePassthroughHandlerValidation(f) |
| self.WritePassthroughServiceFunctionDoerCall(func, f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WritePassthroughImmediateServiceImplementation(self, func, f): |
| """Writes the service implementation for a command.""" |
| self.WritePassthroughServiceFunctionHeader(func, f) |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteImmediateServiceHandlerArgGetCode(func, f) |
| func.WritePassthroughHandlerValidation(f) |
| self.WritePassthroughServiceFunctionDoerCall(func, f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WritePassthroughBucketServiceImplementation(self, func, f): |
| """Writes the service implementation for a command.""" |
| self.WritePassthroughServiceFunctionHeader(func, f) |
| self.WriteHandlerExtensionCheck(func, f) |
| self.WriteBucketServiceHandlerArgGetCode(func, f) |
| func.WritePassthroughHandlerValidation(f) |
| self.WritePassthroughServiceFunctionDoerCall(func, f) |
| f.write(" return error::kNoError;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteHandlerExtensionCheck(self, func, f): |
| if func.GetInfo('extension_flag'): |
| f.write(" if (!features().%s) {\n" % func.GetInfo('extension_flag')) |
| f.write(" return error::kUnknownCommand;") |
| f.write(" }\n\n") |
| |
| def WriteHandlerDeferReadWrite(self, func, f): |
| """Writes the code to handle deferring reads or writes.""" |
| defer_draws = func.GetInfo('defer_draws') |
| defer_reads = func.GetInfo('defer_reads') |
| if defer_draws or defer_reads: |
| f.write(" error::Error error;\n") |
| if defer_draws: |
| f.write(" error = WillAccessBoundFramebufferForDraw();\n") |
| f.write(" if (error != error::kNoError)\n") |
| f.write(" return error;\n") |
| if defer_reads: |
| f.write(" error = WillAccessBoundFramebufferForRead();\n") |
| f.write(" if (error != error::kNoError)\n") |
| f.write(" return error;\n") |
| |
| def WriteValidUnitTest(self, func, f, test, *extras): |
| """Writes a valid unit test for the service implementation.""" |
| if not func.GetInfo('expectation', True): |
| test = self._remove_expected_call_re.sub('', test) |
| name = func.name |
| arg_strings = [ |
| arg.GetValidArg(func) \ |
| for arg in func.GetOriginalArgs() if not arg.IsConstant() |
| ] |
| gl_arg_strings = [ |
| arg.GetValidGLArg(func) \ |
| for arg in func.GetOriginalArgs() |
| ] |
| gl_func_name = func.GetGLTestFunctionName() |
| varz = { |
| 'name': name, |
| 'gl_func_name': gl_func_name, |
| 'args': ", ".join(arg_strings), |
| 'gl_args': ", ".join(gl_arg_strings), |
| } |
| for extra in extras: |
| varz.update(extra) |
| old_test = "" |
| while (old_test != test): |
| old_test = test |
| test = test % varz |
| f.write(test % varz) |
| |
| def WriteInvalidUnitTest(self, func, f, test, *extras): |
| """Writes an invalid unit test for the service implementation.""" |
| if func.IsES3(): |
| return |
| for invalid_arg_index, invalid_arg in enumerate(func.GetOriginalArgs()): |
| # Service implementation does not test constants, as they are not part of |
| # the call in the service side. |
| if invalid_arg.IsConstant(): |
| continue |
| |
| num_invalid_values = invalid_arg.GetNumInvalidValues(func) |
| for value_index in range(0, num_invalid_values): |
| arg_strings = [] |
| parse_result = "kNoError" |
| gl_error = None |
| for arg in func.GetOriginalArgs(): |
| if arg.IsConstant(): |
| continue |
| if invalid_arg is arg: |
| (arg_string, parse_result, gl_error) = arg.GetInvalidArg( |
| value_index) |
| else: |
| arg_string = arg.GetValidArg(func) |
| arg_strings.append(arg_string) |
| gl_arg_strings = [] |
| for arg in func.GetOriginalArgs(): |
| gl_arg_strings.append("_") |
| gl_func_name = func.GetGLTestFunctionName() |
| gl_error_test = '' |
| if not gl_error == None: |
| gl_error_test = '\n EXPECT_EQ(%s, GetGLError());' % gl_error |
| |
| varz = { |
| 'name': func.name, |
| 'arg_index': invalid_arg_index, |
| 'value_index': value_index, |
| 'gl_func_name': gl_func_name, |
| 'args': ", ".join(arg_strings), |
| 'all_but_last_args': ", ".join(arg_strings[:-1]), |
| 'gl_args': ", ".join(gl_arg_strings), |
| 'parse_result': parse_result, |
| 'gl_error_test': gl_error_test, |
| } |
| for extra in extras: |
| varz.update(extra) |
| f.write(test % varz) |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Writes the service unit test for a command.""" |
| |
| if func.name == 'Enable': |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| SetupExpectationsForEnableDisable(%(gl_args)s, true); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s);""" |
| elif func.name == 'Disable': |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| SetupExpectationsForEnableDisable(%(gl_args)s, false); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s);""" |
| else: |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s);""" |
| valid_test += """ |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, valid_test, *extras) |
| |
| if not func.IsES3(): |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0); |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s |
| } |
| """ |
| self.WriteInvalidUnitTest(func, f, invalid_test, *extras) |
| |
| def WriteImmediateServiceUnitTest(self, func, f, *extras): |
| """Writes the service unit test for an immediate command.""" |
| pass |
| |
| def WriteImmediateValidationCode(self, func, f): |
| """Writes the validation code for an immediate version of a command.""" |
| pass |
| |
| def WriteBucketServiceUnitTest(self, func, f, *extras): |
| """Writes the service unit test for a bucket command.""" |
| pass |
| |
| def WriteGLES2ImplementationDeclaration(self, func, f): |
| """Writes the GLES2 Implemention declaration.""" |
| f.write("%s %s(%s) override;\n" % |
| (func.return_type, func.original_name, |
| func.MakeTypedOriginalArgString("", add_default = True))) |
| f.write("\n") |
| |
| def WriteGLES2CLibImplementation(self, func, f): |
| f.write("%s GL_APIENTRY GLES2%s(%s) {\n" % |
| (func.return_type, func.name, |
| func.MakeTypedOriginalArgString(""))) |
| result_string = "return " |
| if func.return_type == "void": |
| result_string = "" |
| f.write(" %sgles2::GetGLContext()->%s(%s);\n" % |
| (result_string, func.original_name, |
| func.MakeOriginalArgString(""))) |
| f.write("}\n") |
| |
| def WriteGLES2Header(self, func, f): |
| """Writes a re-write macro for GLES""" |
| f.write("#define gl%s GLES2_GET_FUN(%s)\n" %(func.name, func.name)) |
| |
| def WriteClientGLCallLog(self, func, f): |
| """Writes a logging macro for the client side code.""" |
| comma = "" |
| if len(func.GetOriginalArgs()): |
| comma = " << " |
| f.write( |
| ' GPU_CLIENT_LOG("[" << GetLogPrefix() << "] %s("%s%s << ")");\n' % |
| (func.prefixed_name, comma, func.MakeLogArgString())) |
| |
| def WriteClientGLReturnLog(self, func, f): |
| """Writes the return value logging code.""" |
| if func.return_type != "void": |
| f.write(' GPU_CLIENT_LOG("return:" << result)\n') |
| |
| def WriteGLES2ImplementationHeader(self, func, f): |
| """Writes the GLES2 Implemention.""" |
| self.WriteGLES2ImplementationDeclaration(func, f) |
| |
| def WriteGLES2TraceImplementationHeader(self, func, f): |
| """Writes the GLES2 Trace Implemention header.""" |
| f.write("%s %s(%s) override;\n" % |
| (func.return_type, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| |
| def WriteGLES2TraceImplementation(self, func, f): |
| """Writes the GLES2 Trace Implemention.""" |
| f.write("%s GLES2TraceImplementation::%s(%s) {\n" % |
| (func.return_type, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| result_string = "return " |
| if func.return_type == "void": |
| result_string = "" |
| f.write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::%s");\n' % |
| func.name) |
| f.write(" %sgl_->%s(%s);\n" % |
| (result_string, func.name, func.MakeOriginalArgString(""))) |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Writes the GLES2 Implemention.""" |
| impl_func = func.GetInfo('impl_func', True) |
| if func.can_auto_generate and impl_func: |
| f.write("%s %sImplementation::%s(%s) {\n" % |
| (func.return_type, _prefix, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| f.write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") |
| self.WriteClientGLCallLog(func, f) |
| func.WriteDestinationInitalizationValidation(f) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| f.write(" helper_->%s(%s);\n" % |
| (func.name, func.MakeHelperArgString(""))) |
| if _prefix != 'WebGPU': |
| f.write(" CheckGLError();\n") |
| self.WriteClientGLReturnLog(func, f) |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteGLES2InterfaceHeader(self, func, f): |
| """Writes the GLES2 Interface.""" |
| f.write("virtual %s %s(%s) = 0;\n" % |
| (func.return_type, func.original_name, |
| func.MakeTypedOriginalArgString("", add_default = True))) |
| |
| def WriteGLES2InterfaceStub(self, func, f): |
| """Writes the GLES2 Interface stub declaration.""" |
| f.write("%s %s(%s) override;\n" % |
| (func.return_type, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| |
| def WriteGLES2InterfaceStubImpl(self, func, f): |
| """Writes the GLES2 Interface stub declaration.""" |
| args = func.GetOriginalArgs() |
| arg_string = ", ".join( |
| ["%s /* %s */" % (arg.type, arg.name) for arg in args]) |
| f.write("%s GLES2InterfaceStub::%s(%s) {\n" % |
| (func.return_type, func.original_name, arg_string)) |
| if func.return_type != "void": |
| f.write(" return 0;\n") |
| f.write("}\n") |
| |
| def WriteGLES2ImplementationUnitTest(self, func, f): |
| """Writes the GLES2 Implemention unit test.""" |
| client_test = func.GetInfo('client_test', True) |
| if func.can_auto_generate and client_test: |
| code = """ |
| TEST_F(%(prefix)sImplementationTest, %(name)s) { |
| struct Cmds { |
| cmds::%(name)s cmd; |
| }; |
| Cmds expected; |
| expected.cmd.Init(%(cmd_args)s); |
| |
| gl_->%(name)s(%(args)s); |
| EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); |
| } |
| """ |
| cmd_arg_strings = [ |
| arg.GetValidClientSideCmdArg(func) for arg in func.GetCmdArgs() |
| ] |
| |
| gl_arg_strings = [ |
| arg.GetValidClientSideArg(func) for arg in func.GetOriginalArgs() |
| ] |
| |
| f.write(code % { |
| 'prefix' : _prefix, |
| 'name': func.name, |
| 'args': ", ".join(gl_arg_strings), |
| 'cmd_args': ", ".join(cmd_arg_strings), |
| }) |
| |
| # Test constants for invalid values, as they are not tested by the |
| # service. |
| constants = [arg for arg in func.GetOriginalArgs() if arg.IsConstant()] |
| if constants: |
| code = """ |
| TEST_F(%(prefix)sImplementationTest, |
| %(name)sInvalidConstantArg%(invalid_index)d) { |
| gl_->%(name)s(%(args)s); |
| EXPECT_TRUE(NoCommandsWritten()); |
| EXPECT_EQ(%(gl_error)s, CheckError()); |
| } |
| """ |
| for invalid_arg in constants: |
| gl_arg_strings = [] |
| invalid = invalid_arg.GetInvalidArg(func) |
| for arg in func.GetOriginalArgs(): |
| if arg is invalid_arg: |
| gl_arg_strings.append(invalid[0]) |
| else: |
| gl_arg_strings.append(arg.GetValidClientSideArg(func)) |
| |
| f.write(code % { |
| 'prefix' : _prefix, |
| 'name': func.name, |
| 'invalid_index': func.GetOriginalArgs().index(invalid_arg), |
| 'args': ", ".join(gl_arg_strings), |
| 'gl_error': invalid[2], |
| }) |
| |
| def WriteDestinationInitalizationValidation(self, func, f): |
| """Writes the client side destintion initialization validation.""" |
| for arg in func.GetOriginalArgs(): |
| arg.WriteDestinationInitalizationValidation(f, func) |
| |
| def WriteTraceEvent(self, func, f): |
| f.write(' TRACE_EVENT0("gpu", "%sImplementation::%s");\n' % |
| (_prefix, func.original_name)) |
| |
| def WriteImmediateCmdComputeSize(self, _func, f): |
| """Writes the size computation code for the immediate version of a cmd.""" |
| f.write(" static uint32_t ComputeSize(uint32_t size_in_bytes) {\n") |
| f.write(" return static_cast<uint32_t>(\n") |
| f.write(" sizeof(ValueType) + // NOLINT\n") |
| f.write(" RoundSizeToMultipleOfEntries(size_in_bytes));\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSetHeader(self, _func, f): |
| """Writes the SetHeader function for the immediate version of a cmd.""" |
| f.write(" void SetHeader(uint32_t size_in_bytes) {\n") |
| f.write(" header.SetCmdByTotalSize<ValueType>(size_in_bytes);\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Writes the Init function for the immediate version of a command.""" |
| raise NotImplementedError(func.name) |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Writes the Set function for the immediate version of a command.""" |
| raise NotImplementedError(func.name) |
| |
| def WriteCmdHelper(self, func, f): |
| """Writes the cmd helper definition for a cmd.""" |
| code = """ void %(name)s(%(typed_args)s) { |
| %(lp)s::cmds::%(name)s* c = GetCmdSpace<%(lp)s::cmds::%(name)s>(); |
| if (c) { |
| c->Init(%(args)s); |
| } |
| } |
| |
| """ |
| f.write(code % { |
| "lp" : _lower_prefix, |
| "name": func.name, |
| "typed_args": func.MakeTypedCmdArgString(""), |
| "args": func.MakeCmdArgString(""), |
| }) |
| |
| def WriteImmediateCmdHelper(self, func, f): |
| """Writes the cmd helper definition for the immediate version of a cmd.""" |
| code = """ void %(name)s(%(typed_args)s) { |
| const uint32_t s = 0; |
| %(lp)s::cmds::%(name)s* c = |
| GetImmediateCmdSpaceTotalSize<%(lp)s::cmds::%(name)s>(s); |
| if (c) { |
| c->Init(%(args)s); |
| } |
| } |
| |
| """ |
| f.write(code % { |
| "lp" : _lower_prefix, |
| "name": func.name, |
| "typed_args": func.MakeTypedCmdArgString(""), |
| "args": func.MakeCmdArgString(""), |
| }) |
| |
| |
| class StateSetHandler(TypeHandler): |
| """Handler for commands that simply set state.""" |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| args = func.GetOriginalArgs() |
| for ndx,item in enumerate(states): |
| code = [] |
| if 'range_checks' in item: |
| for range_check in item['range_checks']: |
| code.append("%s %s" % (args[ndx].name, range_check['check'])) |
| if 'nan_check' in item: |
| # Drivers might generate an INVALID_VALUE error when a value is set |
| # to NaN. This is allowed behavior under GLES 3.0 section 2.1.1 or |
| # OpenGL 4.5 section 2.3.4.1 - providing NaN allows undefined results. |
| # Make this behavior consistent within Chromium, and avoid leaking GL |
| # errors by generating the error in the command buffer instead of |
| # letting the GL driver generate it. |
| code.append("std::isnan(%s)" % args[ndx].name) |
| if len(code): |
| f.write(" if (%s) {\n" % " ||\n ".join(code)) |
| f.write( |
| ' LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,' |
| ' "%s", "%s out of range");\n' % |
| (func.name, args[ndx].name)) |
| f.write(" return error::kNoError;\n") |
| f.write(" }\n") |
| code = [] |
| for ndx,item in enumerate(states): |
| code.append("state_.%s != %s" % (item['name'], args[ndx].name)) |
| f.write(" if (%s) {\n" % " ||\n ".join(code)) |
| for ndx,item in enumerate(states): |
| f.write(" state_.%s = %s;\n" % (item['name'], args[ndx].name)) |
| if 'on_change' in state: |
| f.write(" %s\n" % state['on_change']) |
| if not func.GetInfo("no_gl"): |
| for ndx,item in enumerate(states): |
| if item.get('cached', False): |
| f.write(" state_.%s = %s;\n" % |
| (CachedStateName(item), args[ndx].name)) |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| f.write(" }\n") |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| TypeHandler.WriteServiceUnitTest(self, func, f, *extras) |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| for ndx,item in enumerate(states): |
| if 'range_checks' in item: |
| for check_ndx, range_check in enumerate(item['range_checks']): |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidValue%(ndx)d_%(check_ndx)d) { |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| """ |
| name = func.name |
| arg_strings = [ |
| arg.GetValidArg(func) \ |
| for arg in func.GetOriginalArgs() if not arg.IsConstant() |
| ] |
| |
| arg_strings[ndx] = range_check['test_value'] |
| varz = { |
| 'name': name, |
| 'ndx': ndx, |
| 'check_ndx': check_ndx, |
| 'args': ", ".join(arg_strings), |
| } |
| for extra in extras: |
| varz.update(extra) |
| f.write(valid_test % varz) |
| if 'nan_check' in item: |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sNaNValue%(ndx)d) { |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| """ |
| name = func.name |
| arg_strings = [ |
| arg.GetValidArg(func) \ |
| for arg in func.GetOriginalArgs() if not arg.IsConstant() |
| ] |
| |
| arg_strings[ndx] = 'nanf("")' |
| varz = { |
| 'name': name, |
| 'ndx': ndx, |
| 'args': ", ".join(arg_strings), |
| } |
| for extra in extras: |
| varz.update(extra) |
| f.write(valid_test % varz) |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class StateSetRGBAlphaHandler(TypeHandler): |
| """Handler for commands that simply set state that have rgb/alpha.""" |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| args = func.GetOriginalArgs() |
| num_args = len(args) |
| code = [] |
| for ndx,item in enumerate(states): |
| code.append("state_.%s != %s" % (item['name'], args[ndx % num_args].name)) |
| f.write(" if (%s) {\n" % " ||\n ".join(code)) |
| for ndx, item in enumerate(states): |
| f.write(" state_.%s = %s;\n" % |
| (item['name'], args[ndx % num_args].name)) |
| if 'on_change' in state: |
| f.write(" %s\n" % state['on_change']) |
| if not func.GetInfo("no_gl"): |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| f.write(" }\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class StateSetFrontBackSeparateHandler(TypeHandler): |
| """Handler for commands that simply set state that have front/back.""" |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| args = func.GetOriginalArgs() |
| face = args[0].name |
| num_args = len(args) |
| f.write(" bool changed = false;\n") |
| for group_ndx, group in enumerate(Grouper(num_args - 1, states)): |
| f.write(" if (%s == %s || %s == GL_FRONT_AND_BACK) {\n" % |
| (face, ('GL_FRONT', 'GL_BACK')[group_ndx], face)) |
| code = [] |
| for ndx, item in enumerate(group): |
| code.append("state_.%s != %s" % (item['name'], args[ndx + 1].name)) |
| f.write(" changed |= %s;\n" % " ||\n ".join(code)) |
| f.write(" }\n") |
| f.write(" if (changed) {\n") |
| for group_ndx, group in enumerate(Grouper(num_args - 1, states)): |
| f.write(" if (%s == %s || %s == GL_FRONT_AND_BACK) {\n" % |
| (face, ('GL_FRONT', 'GL_BACK')[group_ndx], face)) |
| for ndx, item in enumerate(group): |
| f.write(" state_.%s = %s;\n" % |
| (item['name'], args[ndx + 1].name)) |
| f.write(" }\n") |
| if 'on_change' in state: |
| f.write(" %s\n" % state['on_change']) |
| if not func.GetInfo("no_gl"): |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| f.write(" }\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class StateSetFrontBackHandler(TypeHandler): |
| """Handler for commands that simply set state that set both front/back.""" |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| args = func.GetOriginalArgs() |
| num_args = len(args) |
| code = [] |
| for group in Grouper(num_args, states): |
| for ndx, item in enumerate(group): |
| code.append("state_.%s != %s" % (item['name'], args[ndx].name)) |
| f.write(" if (%s) {\n" % " ||\n ".join(code)) |
| for group in Grouper(num_args, states): |
| for ndx, item in enumerate(group): |
| f.write(" state_.%s = %s;\n" % (item['name'], args[ndx].name)) |
| if 'on_change' in state: |
| f.write(" %s\n" % state['on_change']) |
| if not func.GetInfo("no_gl"): |
| f.write(" %s(%s);\n" % |
| (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) |
| f.write(" }\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class StateSetNamedParameter(TypeHandler): |
| """Handler for commands that set a state chosen with an enum parameter.""" |
| |
| def WriteHandlerImplementation(self, func, f): |
| """Overridden from TypeHandler.""" |
| state_name = func.GetInfo('state') |
| state = _STATE_INFO[state_name] |
| states = state['states'] |
| args = func.GetOriginalArgs() |
| num_args = len(args) |
| assert num_args == 2 |
| f.write(" switch (%s) {\n" % args[0].name) |
| for state in states: |
| f.write(" case %s:\n" % state['enum']) |
| f.write(" if (state_.%s != %s) {\n" % |
| (state['name'], args[1].name)) |
| f.write(" state_.%s = %s;\n" % (state['name'], args[1].name)) |
| if not func.GetInfo("no_gl"): |
| operation = " %s(%s);\n" % \ |
| (func.GetGLFunctionName(), func.MakeOriginalArgString("")) |
| f.write(GuardState(state, operation)) |
| f.write(" }\n") |
| f.write(" break;\n") |
| f.write(" default:\n") |
| f.write(" NOTREACHED();\n") |
| f.write(" }\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class CustomHandler(TypeHandler): |
| """Handler for commands that are auto-generated but require minor tweaks.""" |
| |
| def InitFunction(self, func): |
| """Overrriden from TypeHandler.""" |
| if (func.name.startswith('CompressedTex') and func.name.endswith('Bucket')): |
| # Remove imageSize argument, take the size from the bucket instead. |
| func.cmd_args = [arg for arg in func.cmd_args if arg.name != 'imageSize'] |
| func.AddCmdArg(Argument('bucket_id', 'GLuint')) |
| else: |
| TypeHandler.InitFunction(self, func) |
| |
| def WriteServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteBucketServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WritePassthroughServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WritePassthroughImmediateServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WritePassthroughBucketServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdGetTotalSize(self, _func, f): |
| """Overrriden from TypeHandler.""" |
| f.write( |
| " uint32_t total_size = 0; // WARNING: compute correct size.\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" void Init(%s) {\n" % func.MakeTypedCmdArgString("_")) |
| self.WriteImmediateCmdGetTotalSize(func, f) |
| f.write(" SetHeader(total_size);\n") |
| args = func.GetCmdArgs() |
| for arg in args: |
| arg.WriteSetCode(f, 4, '_%s' % arg.name) |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| copy_args = func.MakeCmdArgString("_", False) |
| f.write(" void* Set(void* cmd%s) {\n" % |
| func.MakeTypedCmdArgString("_", True)) |
| self.WriteImmediateCmdGetTotalSize(func, f) |
| f.write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % copy_args) |
| f.write(" return NextImmediateCmdAddressTotalSize<ValueType>(" |
| "cmd, total_size);\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| |
| class NoCommandHandler(CustomHandler): |
| """Handler for functions that don't use commands""" |
| |
| def WriteGLES2Implementation(self, func, f): |
| pass |
| |
| def WriteGLES2ImplementationUnitTest(self, func, f): |
| pass |
| |
| |
| class DataHandler(TypeHandler): |
| """ |
| Handler for glBufferData, glBufferSubData, glTex{Sub}Image*D. |
| """ |
| |
| def WriteGetDataSizeCode(self, func, arg, f): |
| """Overrriden from TypeHandler.""" |
| # TODO: Move this data to _FUNCTION_INFO? |
| name = func.name |
| if name.endswith("Immediate"): |
| name = name[0:-9] |
| if arg.name in func.size_args: |
| size = func.size_args[arg.name] |
| f.write(" uint32_t %s = %s;\n" % (arg.GetReservedSizeId(), size)) |
| else: |
| f.write("// uint32_t %s = 0; // WARNING: compute correct size.\n" % ( |
| arg.GetReservedSizeId())) |
| |
| def WriteImmediateCmdGetTotalSize(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" void Init(%s) {\n" % func.MakeTypedCmdArgString("_")) |
| self.WriteImmediateCmdGetTotalSize(func, f) |
| f.write(" SetHeader(total_size);\n") |
| args = func.GetCmdArgs() |
| for arg in args: |
| f.write(" %s = _%s;\n" % (arg.name, arg.name)) |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| copy_args = func.MakeCmdArgString("_", False) |
| f.write(" void* Set(void* cmd%s) {\n" % |
| func.MakeTypedCmdArgString("_", True)) |
| self.WriteImmediateCmdGetTotalSize(func, f) |
| f.write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % copy_args) |
| f.write(" return NextImmediateCmdAddressTotalSize<ValueType>(" |
| "cmd, total_size);\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateFormatTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| # TODO: Remove this exception. |
| return |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class BindHandler(TypeHandler): |
| """Handler for glBind___ type functions.""" |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| |
| if len(func.GetOriginalArgs()) == 1: |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| """ |
| if func.GetInfo("gen_func"): |
| valid_test += """ |
| TEST_P(%(test_name)s, %(name)sValidArgsNewId) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(kNewServiceId)); |
| EXPECT_CALL(*gl_, %(gl_gen_func_name)s(1, _)) |
| .WillOnce(SetArgPointee<1>(kNewServiceId)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(Get%(resource_type)s(kNewClientId) != nullptr); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'resource_type': func.GetOriginalArgs()[0].resource_type, |
| 'gl_gen_func_name': func.GetInfo("gen_func"), |
| }, *extras) |
| else: |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| """ |
| if func.GetInfo("gen_func"): |
| valid_test += """ |
| TEST_P(%(test_name)s, %(name)sValidArgsNewId) { |
| EXPECT_CALL(*gl_, |
| %(gl_func_name)s(%(gl_args_with_new_id)s)); |
| EXPECT_CALL(*gl_, %(gl_gen_func_name)s(1, _)) |
| .WillOnce(SetArgPointee<1>(kNewServiceId)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args_with_new_id)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(Get%(resource_type)s(kNewClientId) != nullptr); |
| } |
| """ |
| |
| gl_args_with_new_id = [] |
| args_with_new_id = [] |
| for arg in func.GetOriginalArgs(): |
| if hasattr(arg, 'resource_type'): |
| gl_args_with_new_id.append('kNewServiceId') |
| args_with_new_id.append('kNewClientId') |
| else: |
| gl_args_with_new_id.append(arg.GetValidGLArg(func)) |
| args_with_new_id.append(arg.GetValidArg(func)) |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'args_with_new_id': ", ".join(args_with_new_id), |
| 'gl_args_with_new_id': ", ".join(gl_args_with_new_id), |
| 'resource_type': func.GetResourceIdArg().resource_type, |
| 'gl_gen_func_name': func.GetInfo("gen_func"), |
| }, *extras) |
| |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0); |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s |
| } |
| """ |
| self.WriteInvalidUnitTest(func, f, invalid_test, *extras) |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Writes the GLES2 Implemention.""" |
| |
| impl_func = func.GetInfo('impl_func', True) |
| if func.can_auto_generate and impl_func: |
| f.write("%s %sImplementation::%s(%s) {\n" % |
| (func.return_type, _prefix, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| f.write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") |
| func.WriteDestinationInitalizationValidation(f) |
| self.WriteClientGLCallLog(func, f) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| |
| code = """ if (Is%(type)sReservedId(%(id)s)) { |
| SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id"); |
| return; |
| } |
| %(name)sHelper(%(arg_string)s); |
| CheckGLError(); |
| } |
| |
| """ |
| name_arg = func.GetResourceIdArg() |
| f.write(code % { |
| 'name': func.name, |
| 'arg_string': func.MakeOriginalArgString(""), |
| 'id': name_arg.name, |
| 'type': name_arg.resource_type, |
| 'lc_type': name_arg.resource_type.lower(), |
| }) |
| |
| def WriteGLES2ImplementationUnitTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| client_test = func.GetInfo('client_test', True) |
| if not client_test: |
| return |
| code = """ |
| TEST_F(%(prefix)sImplementationTest, %(name)s) { |
| struct Cmds { |
| cmds::%(name)s cmd; |
| }; |
| Cmds expected; |
| expected.cmd.Init(%(cmd_args)s); |
| |
| gl_->%(name)s(%(args)s); |
| EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));""" |
| if not func.IsES3(): |
| code += """ |
| ClearCommands(); |
| gl_->%(name)s(%(args)s); |
| EXPECT_TRUE(NoCommandsWritten());""" |
| code += """ |
| } |
| """ |
| cmd_arg_strings = [ |
| arg.GetValidClientSideCmdArg(func) for arg in func.GetCmdArgs() |
| ] |
| gl_arg_strings = [ |
| arg.GetValidClientSideArg(func) for arg in func.GetOriginalArgs() |
| ] |
| |
| f.write(code % { |
| 'prefix' : _prefix, |
| 'name': func.name, |
| 'args': ", ".join(gl_arg_strings), |
| 'cmd_args': ", ".join(cmd_arg_strings), |
| }) |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class GENnHandler(TypeHandler): |
| """Handler for glGen___ type functions.""" |
| |
| def InitFunction(self, func): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteGetDataSizeCode(self, func, arg, f): |
| """Overrriden from TypeHandler.""" |
| code = """ uint32_t %(data_size)s; |
| if (!%(namespace)sSafeMultiplyUint32(n, sizeof(GLuint), &%(data_size)s)) { |
| return error::kOutOfBounds; |
| } |
| """ % {'data_size': arg.GetReservedSizeId(), |
| 'namespace': _Namespace()} |
| f.write(code) |
| |
| def WriteHandlerImplementation (self, func, f): |
| """Overrriden from TypeHandler.""" |
| raise NotImplementedError("GENn functions are immediate") |
| |
| def WriteImmediateHandlerImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| param_name = func.GetLastOriginalArg().name |
| f.write(" auto %(name)s_copy = std::make_unique<GLuint[]>(n);\n" |
| " GLuint* %(name)s_safe = %(name)s_copy.get();\n" |
| " std::copy(%(name)s, %(name)s + n, %(name)s_safe);\n" |
| " if (!%(ns)sCheckUniqueAndNonNullIds(n, %(name)s_safe) ||\n" |
| " !%(func)sHelper(n, %(name)s_safe)) {\n" |
| " return error::kInvalidArguments;\n" |
| " }\n" % {'name': param_name, |
| 'func': func.original_name, |
| 'ns': _Namespace()}) |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| log_code = (""" GPU_CLIENT_LOG_CODE_BLOCK({ |
| for (GLsizei i = 0; i < n; ++i) { |
| GPU_CLIENT_LOG(" " << i << ": " << %s[i]); |
| } |
| });""" % func.GetOriginalArgs()[1].name) |
| args = { |
| 'log_code': log_code, |
| 'return_type': func.return_type, |
| 'prefix' : _prefix, |
| 'name': func.original_name, |
| 'typed_args': func.MakeTypedOriginalArgString(""), |
| 'args': func.MakeOriginalArgString(""), |
| 'resource_types': func.GetInfo('resource_types'), |
| 'count_name': func.GetOriginalArgs()[0].name, |
| } |
| f.write( |
| "%(return_type)s %(prefix)sImplementation::" |
| "%(name)s(%(typed_args)s) {\n" % |
| args) |
| func.WriteDestinationInitalizationValidation(f) |
| self.WriteClientGLCallLog(func, f) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| not_shared = func.GetInfo('not_shared') |
| if not_shared: |
| alloc_code = ("""\ |
| IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::k%s); |
| for (GLsizei ii = 0; ii < n; ++ii) |
| %s[ii] = id_allocator->AllocateID();""" % |
| (func.GetInfo('resource_types'), func.GetOriginalArgs()[1].name)) |
| else: |
| alloc_code = ("""\ |
| GetIdHandler(SharedIdNamespaces::k%(resource_types)s)-> |
| MakeIds(this, 0, %(args)s);""" % args) |
| args['alloc_code'] = alloc_code |
| |
| code = """\ |
| GPU_CLIENT_SINGLE_THREAD_CHECK(); |
| %(alloc_code)s |
| %(name)sHelper(%(args)s); |
| helper_->%(name)sImmediate(%(args)s); |
| """ |
| if not not_shared: |
| code += """\ |
| if (share_group_->bind_generates_resource()) |
| helper_->CommandBufferHelper::Flush(); |
| """ |
| code += """\ |
| %(log_code)s |
| CheckGLError(); |
| } |
| |
| """ |
| f.write(code % args) |
| |
| def WriteGLES2ImplementationUnitTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| code = """ |
| TEST_F(%(prefix)sImplementationTest, %(name)s) { |
| GLuint ids[2] = { 0, }; |
| struct Cmds { |
| cmds::%(name)sImmediate gen; |
| GLuint data[2]; |
| }; |
| Cmds expected; |
| expected.gen.Init(base::size(ids), &ids[0]); |
| expected.data[0] = k%(types)sStartId; |
| expected.data[1] = k%(types)sStartId + 1; |
| gl_->%(name)s(base::size(ids), &ids[0]); |
| EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); |
| EXPECT_EQ(k%(types)sStartId, ids[0]); |
| EXPECT_EQ(k%(types)sStartId + 1, ids[1]); |
| } |
| """ |
| f.write(code % { |
| 'prefix' : _prefix, |
| 'name': func.name, |
| 'types': func.GetInfo('resource_types'), |
| }) |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| raise NotImplementedError("GENn functions are immediate") |
| |
| def WriteImmediateServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(1, _)) |
| .WillOnce(SetArgPointee<1>(kNewServiceId)); |
| cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>(); |
| GLuint temp = kNewClientId; |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmd->Init(1, &temp); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(*cmd, sizeof(temp))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(Get%(resource_name)s(kNewClientId) != nullptr); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'resource_name': func.GetInfo('resource_type'), |
| }, *extras) |
| duplicate_id_test = """ |
| TEST_P(%(test_name)s, %(name)sDuplicateOrNullIds) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(_, _)).Times(0); |
| cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>(); |
| GLuint temp[3] = {kNewClientId, kNewClientId + 1, kNewClientId}; |
| SpecializedSetup<cmds::%(name)s, 1>(true); |
| cmd->Init(3, temp); |
| EXPECT_EQ(error::kInvalidArguments, |
| ExecuteImmediateCmd(*cmd, sizeof(temp))); |
| EXPECT_TRUE(Get%(resource_name)s(kNewClientId) == nullptr); |
| EXPECT_TRUE(Get%(resource_name)s(kNewClientId + 1) == nullptr); |
| GLuint null_id[2] = {kNewClientId, 0}; |
| cmd->Init(2, null_id); |
| EXPECT_EQ(error::kInvalidArguments, |
| ExecuteImmediateCmd(*cmd, sizeof(temp))); |
| EXPECT_TRUE(Get%(resource_name)s(kNewClientId) == nullptr); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, duplicate_id_test, { |
| 'resource_name': func.GetInfo('resource_type'), |
| }, *extras) |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(_, _)).Times(0); |
| cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>(); |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmd->Init(1, &client_%(resource_name)s_id_); |
| EXPECT_EQ(error::kInvalidArguments, |
| ExecuteImmediateCmd(*cmd, sizeof(&client_%(resource_name)s_id_))); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, invalid_test, { |
| 'resource_name': func.GetInfo('resource_type').lower(), |
| }, *extras) |
| |
| def WriteImmediateCmdComputeSize(self, _func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" static uint32_t ComputeDataSize(GLsizei _n) {\n") |
| f.write( |
| " return static_cast<uint32_t>(sizeof(GLuint) * _n); // NOLINT\n") |
| f.write(" }\n") |
| f.write("\n") |
| f.write(" static uint32_t ComputeSize(GLsizei _n) {\n") |
| f.write(" return static_cast<uint32_t>(\n") |
| f.write(" sizeof(ValueType) + ComputeDataSize(_n)); // NOLINT\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSetHeader(self, _func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" void SetHeader(GLsizei _n) {\n") |
| f.write(" header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| last_arg = func.GetLastOriginalArg() |
| f.write(" void Init(%s, %s _%s) {\n" % |
| (func.MakeTypedCmdArgString("_"), |
| last_arg.type, last_arg.name)) |
| f.write(" SetHeader(_n);\n") |
| args = func.GetCmdArgs() |
| for arg in args: |
| f.write(" %s = _%s;\n" % (arg.name, arg.name)) |
| f.write(" memcpy(ImmediateDataAddress(this),\n") |
| f.write(" _%s, ComputeDataSize(_n));\n" % last_arg.name) |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| last_arg = func.GetLastOriginalArg() |
| copy_args = func.MakeCmdArgString("_", False) |
| f.write(" void* Set(void* cmd%s, %s _%s) {\n" % |
| (func.MakeTypedCmdArgString("_", True), |
| last_arg.type, last_arg.name)) |
| f.write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" % |
| (copy_args, last_arg.name)) |
| f.write(" const uint32_t size = ComputeSize(_n);\n") |
| f.write(" return NextImmediateCmdAddressTotalSize<ValueType>(" |
| "cmd, size);\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdHelper(self, func, f): |
| """Overrriden from TypeHandler.""" |
| code = """ void %(name)s(%(typed_args)s) { |
| const uint32_t size = %(lp)s::cmds::%(name)s::ComputeSize(n); |
| %(lp)s::cmds::%(name)s* c = |
| GetImmediateCmdSpaceTotalSize<%(lp)s::cmds::%(name)s>(size); |
| if (c) { |
| c->Init(%(args)s); |
| } |
| } |
| |
| """ |
| f.write(code % { |
| "lp" : _lower_prefix, |
| "name": func.name, |
| "typed_args": func.MakeTypedOriginalArgString(""), |
| "args": func.MakeOriginalArgString(""), |
| }) |
| |
| def WriteImmediateFormatTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name)) |
| f.write(" static GLuint ids[] = { 12, 23, 34, };\n") |
| f.write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" % |
| (func.name, func.name)) |
| f.write(" void* next_cmd = cmd.Set(\n") |
| f.write(" &cmd, static_cast<GLsizei>(base::size(ids)), ids);\n") |
| f.write(" EXPECT_EQ(static_cast<uint32_t>(cmds::%s::kCmdId),\n" % |
| func.name) |
| f.write(" cmd.header.command);\n") |
| f.write(" EXPECT_EQ(sizeof(cmd) +\n") |
| f.write(" RoundSizeToMultipleOfEntries(cmd.n * 4u),\n") |
| f.write(" cmd.header.size * 4u);\n") |
| f.write(" EXPECT_EQ(static_cast<GLsizei>(base::size(ids)), cmd.n);\n"); |
| f.write(" CheckBytesWrittenMatchesExpectedSize(\n") |
| f.write(" next_cmd, sizeof(cmd) +\n") |
| f.write(" RoundSizeToMultipleOfEntries(base::size(ids) * 4u));\n") |
| f.write(" EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd),\n") |
| f.write(" sizeof(ids)));\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| |
| class CreateHandler(TypeHandler): |
| """Handler for glCreate___ type functions.""" |
| |
| def InitFunction(self, func): |
| """Overrriden from TypeHandler.""" |
| func.AddCmdArg(Argument("client_id", 'uint32_t')) |
| |
| def __GetResourceType(self, func): |
| if func.return_type == "GLsync": |
| return "Sync" |
| else: |
| return func.name[6:] # Create* |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| %(id_type_cast)sEXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)) |
| .WillOnce(Return(%(const_service_id)s)); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s%(comma)skNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError());""" |
| if func.IsES3(): |
| valid_test += """ |
| %(return_type)s service_id = 0; |
| EXPECT_TRUE(Get%(resource_type)sServiceId(kNewClientId, &service_id)); |
| EXPECT_EQ(%(const_service_id)s, service_id); |
| } |
| """ |
| else: |
| valid_test += """ |
| EXPECT_TRUE(Get%(resource_type)s(kNewClientId)); |
| } |
| """ |
| comma = "" |
| cmd_arg_count = 0 |
| for arg in func.GetOriginalArgs(): |
| if not arg.IsConstant(): |
| cmd_arg_count += 1 |
| if cmd_arg_count: |
| comma = ", " |
| if func.return_type == 'GLsync': |
| id_type_cast = ("const GLsync kNewServiceIdGLuint = reinterpret_cast" |
| "<GLsync>(kNewServiceId);\n ") |
| const_service_id = "kNewServiceIdGLuint" |
| else: |
| id_type_cast = "" |
| const_service_id = "kNewServiceId" |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'comma': comma, |
| 'resource_type': self.__GetResourceType(func), |
| 'return_type': func.return_type, |
| 'id_type_cast': id_type_cast, |
| 'const_service_id': const_service_id, |
| }, *extras) |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { |
| EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0); |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s%(comma)skNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));%(gl_error_test)s |
| } |
| """ |
| self.WriteInvalidUnitTest(func, f, invalid_test, { |
| 'comma': comma, |
| }, *extras) |
| |
| def WriteHandlerImplementation (self, func, f): |
| """Overrriden from TypeHandler.""" |
| if func.IsES3(): |
| code = """ uint32_t client_id = c.client_id; |
| %(return_type)s service_id = 0; |
| if (group_->Get%(resource_name)sServiceId(client_id, &service_id)) { |
| return error::kInvalidArguments; |
| } |
| service_id = %(gl_func_name)s(%(gl_args)s); |
| if (service_id) { |
| group_->Add%(resource_name)sId(client_id, service_id); |
| } |
| """ |
| else: |
| code = """ uint32_t client_id = c.client_id; |
| if (Get%(resource_name)s(client_id)) { |
| return error::kInvalidArguments; |
| } |
| %(return_type)s service_id = %(gl_func_name)s(%(gl_args)s); |
| if (service_id) { |
| Create%(resource_name)s(client_id, service_id%(gl_args_with_comma)s); |
| } |
| """ |
| f.write(code % { |
| 'resource_name': self.__GetResourceType(func), |
| 'return_type': func.return_type, |
| 'gl_func_name': func.GetGLFunctionName(), |
| 'gl_args': func.MakeOriginalArgString(""), |
| 'gl_args_with_comma': func.MakeOriginalArgString("", True) }) |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write("%s %sImplementation::%s(%s) {\n" % |
| (func.return_type, _prefix, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| f.write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") |
| func.WriteDestinationInitalizationValidation(f) |
| self.WriteClientGLCallLog(func, f) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| f.write(" GLuint client_id;\n") |
| not_shared = func.GetInfo('not_shared') |
| if not_shared: |
| f.write('IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::k%s);' % |
| func.GetInfo('resource_types')) |
| f.write('client_id = id_allocator->AllocateID();') |
| else: |
| if func.return_type == "GLsync": |
| f.write( |
| " GetIdHandler(SharedIdNamespaces::kSyncs)->\n") |
| else: |
| f.write( |
| " GetIdHandler(SharedIdNamespaces::kProgramsAndShaders)->\n") |
| f.write(" MakeIds(this, 0, 1, &client_id);\n") |
| f.write(" helper_->%s(%s);\n" % |
| (func.name, func.MakeCmdArgString(""))) |
| f.write(' GPU_CLIENT_LOG("returned " << client_id);\n') |
| f.write(" CheckGLError();\n") |
| if func.return_type == "GLsync": |
| f.write(" return reinterpret_cast<GLsync>(client_id);\n") |
| else: |
| f.write(" return client_id;\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WritePassthroughServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class DeleteHandler(TypeHandler): |
| """Handler for glDelete___ single resource type functions.""" |
| |
| def WriteServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| if func.IsES3(): |
| TypeHandler.WriteServiceImplementation(self, func, f) |
| # HandleDeleteShader and HandleDeleteProgram are manually written. |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write("%s %sImplementation::%s(%s) {\n" % |
| (func.return_type, _prefix, func.original_name, |
| func.MakeTypedOriginalArgString(""))) |
| f.write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") |
| func.WriteDestinationInitalizationValidation(f) |
| self.WriteClientGLCallLog(func, f) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| f.write( |
| " if (%s == 0)\n return;" % func.GetOriginalArgs()[-1].name); |
| f.write(" %sHelper(%s);\n" % |
| (func.original_name, func.GetOriginalArgs()[-1].name)) |
| f.write(" CheckGLError();\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| def WriteHandlerImplementation (self, func, f): |
| """Overrriden from TypeHandler.""" |
| assert len(func.GetOriginalArgs()) == 1 |
| arg = func.GetOriginalArgs()[0] |
| f.write(" %sHelper(%s);\n" % (func.original_name, arg.name)) |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| pass |
| |
| |
| class DELnHandler(TypeHandler): |
| """Handler for glDelete___ type functions.""" |
| |
| def WriteGetDataSizeCode(self, func, arg, f): |
| """Overrriden from TypeHandler.""" |
| code = """ uint32_t %(data_size)s; |
| if (!%(namespace)sSafeMultiplyUint32(n, sizeof(GLuint), &%(data_size)s)) { |
| return error::kOutOfBounds; |
| } |
| """ % {'data_size': arg.GetReservedSizeId(), |
| 'namespace': _Namespace()} |
| f.write(code) |
| |
| def WriteGLES2ImplementationUnitTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| code = """ |
| TEST_F(%(prefix)sImplementationTest, %(name)s) { |
| GLuint ids[2] = { k%(types)sStartId, k%(types)sStartId + 1 }; |
| struct Cmds { |
| cmds::%(name)sImmediate del; |
| GLuint data[2]; |
| }; |
| Cmds expected; |
| expected.del.Init(base::size(ids), &ids[0]); |
| expected.data[0] = k%(types)sStartId; |
| expected.data[1] = k%(types)sStartId + 1; |
| gl_->%(name)s(base::size(ids), &ids[0]); |
| EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); |
| } |
| """ |
| f.write(code % { |
| 'prefix' : _prefix, |
| 'name': func.name, |
| 'types': func.GetInfo('resource_types'), |
| }) |
| |
| def WriteServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL( |
| *gl_, |
| %(gl_func_name)s(1, Pointee(kService%(upper_resource_name)sId))) |
| .Times(1); |
| GetSharedMemoryAs<GLuint*>()[0] = client_%(resource_name)s_id_; |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE( |
| Get%(upper_resource_name)s(client_%(resource_name)s_id_) == nullptr); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'resource_name': func.GetInfo('resource_type').lower(), |
| 'upper_resource_name': func.GetInfo('resource_type'), |
| }, *extras) |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs) { |
| GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId; |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| cmds::%(name)s cmd; |
| cmd.Init(%(args)s); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, invalid_test, *extras) |
| |
| def WriteImmediateServiceUnitTest(self, func, f, *extras): |
| """Overrriden from TypeHandler.""" |
| valid_test = """ |
| TEST_P(%(test_name)s, %(name)sValidArgs) { |
| EXPECT_CALL( |
| *gl_, |
| %(gl_func_name)s(1, Pointee(kService%(upper_resource_name)sId))) |
| .Times(1); |
| cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>(); |
| SpecializedSetup<cmds::%(name)s, 0>(true); |
| cmd.Init(1, &client_%(resource_name)s_id_); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(client_%(resource_name)s_id_))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE( |
| Get%(upper_resource_name)s(client_%(resource_name)s_id_) == nullptr); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, valid_test, { |
| 'resource_name': func.GetInfo('resource_type').lower(), |
| 'upper_resource_name': func.GetInfo('resource_type'), |
| }, *extras) |
| invalid_test = """ |
| TEST_P(%(test_name)s, %(name)sInvalidArgs) { |
| cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>(); |
| SpecializedSetup<cmds::%(name)s, 0>(false); |
| GLuint temp = kInvalidClientId; |
| cmd.Init(1, &temp); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(temp))); |
| } |
| """ |
| self.WriteValidUnitTest(func, f, invalid_test, *extras) |
| |
| def WriteHandlerImplementation (self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" %sHelper(n, %s);\n" % |
| (func.name, func.GetLastOriginalArg().name)) |
| |
| def WriteImmediateHandlerImplementation (self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" %sHelper(n, %s);\n" % |
| (func.original_name, func.GetLastOriginalArg().name)) |
| |
| def WriteGLES2Implementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| impl_func = func.GetInfo('impl_func', True) |
| if impl_func: |
| args = { |
| 'return_type': func.return_type, |
| 'prefix' : _prefix, |
| 'name': func.original_name, |
| 'typed_args': func.MakeTypedOriginalArgString(""), |
| 'args': func.MakeOriginalArgString(""), |
| 'resource_type': func.GetInfo('resource_type').lower(), |
| 'count_name': func.GetOriginalArgs()[0].name, |
| } |
| f.write( |
| "%(return_type)s %(prefix)sImplementation::" |
| "%(name)s(%(typed_args)s) {\n" % |
| args) |
| f.write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") |
| func.WriteDestinationInitalizationValidation(f) |
| self.WriteClientGLCallLog(func, f) |
| f.write(""" GPU_CLIENT_LOG_CODE_BLOCK({ |
| for (GLsizei i = 0; i < n; ++i) { |
| GPU_CLIENT_LOG(" " << i << ": " << %s[i]); |
| } |
| }); |
| """ % func.GetOriginalArgs()[1].name) |
| f.write(""" GPU_CLIENT_DCHECK_CODE_BLOCK({ |
| for (GLsizei i = 0; i < n; ++i) { |
| DCHECK(%s[i] != 0); |
| } |
| }); |
| """ % func.GetOriginalArgs()[1].name) |
| for arg in func.GetOriginalArgs(): |
| arg.WriteClientSideValidationCode(f, func) |
| code = """ %(name)sHelper(%(args)s); |
| CheckGLError(); |
| } |
| |
| """ |
| f.write(code % args) |
| |
| def WriteImmediateCmdComputeSize(self, _func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" static uint32_t ComputeDataSize(GLsizei _n) {\n") |
| f.write( |
| " return static_cast<uint32_t>(sizeof(GLuint) * _n); // NOLINT\n") |
| f.write(" }\n") |
| f.write("\n") |
| f.write(" static uint32_t ComputeSize(GLsizei _n) {\n") |
| f.write(" return static_cast<uint32_t>(\n") |
| f.write(" sizeof(ValueType) + ComputeDataSize(_n)); // NOLINT\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSetHeader(self, _func, f): |
| """Overrriden from TypeHandler.""" |
| f.write(" void SetHeader(GLsizei _n) {\n") |
| f.write(" header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdInit(self, func, f): |
| """Overrriden from TypeHandler.""" |
| last_arg = func.GetLastOriginalArg() |
| f.write(" void Init(%s, %s _%s) {\n" % |
| (func.MakeTypedCmdArgString("_"), |
| last_arg.type, last_arg.name)) |
| f.write(" SetHeader(_n);\n") |
| args = func.GetCmdArgs() |
| for arg in args: |
| f.write(" %s = _%s;\n" % (arg.name, arg.name)) |
| f.write(" memcpy(ImmediateDataAddress(this),\n") |
| f.write(" _%s, ComputeDataSize(_n));\n" % last_arg.name) |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdSet(self, func, f): |
| """Overrriden from TypeHandler.""" |
| last_arg = func.GetLastOriginalArg() |
| copy_args = func.MakeCmdArgString("_", False) |
| f.write(" void* Set(void* cmd%s, %s _%s) {\n" % |
| (func.MakeTypedCmdArgString("_", True), |
| last_arg.type, last_arg.name)) |
| f.write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" % |
| (copy_args, last_arg.name)) |
| f.write(" const uint32_t size = ComputeSize(_n);\n") |
| f.write(" return NextImmediateCmdAddressTotalSize<ValueType>(" |
| "cmd, size);\n") |
| f.write(" }\n") |
| f.write("\n") |
| |
| def WriteImmediateCmdHelper(self, func, f): |
| """Overrriden from TypeHandler.""" |
| code = """ void %(name)s(%(typed_args)s) { |
| const uint32_t size = %(lp)s::cmds::%(name)s::ComputeSize(n); |
| %(lp)s::cmds::%(name)s* c = |
| GetImmediateCmdSpaceTotalSize<%(lp)s::cmds::%(name)s>(size); |
| if (c) { |
| c->Init(%(args)s); |
| } |
| } |
| |
| """ |
| f.write(code % { |
| "lp" : _lower_prefix, |
| "name": func.name, |
| "typed_args": func.MakeTypedOriginalArgString(""), |
| "args": func.MakeOriginalArgString(""), |
| }) |
| |
| def WriteImmediateFormatTest(self, func, f): |
| """Overrriden from TypeHandler.""" |
| f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name)) |
| f.write(" static GLuint ids[] = { 12, 23, 34, };\n") |
| f.write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" % |
| (func.name, func.name)) |
| f.write(" void* next_cmd = cmd.Set(\n") |
| f.write(" &cmd, static_cast<GLsizei>(base::size(ids)), ids);\n") |
| f.write(" EXPECT_EQ(static_cast<uint32_t>(cmds::%s::kCmdId),\n" % |
| func.name) |
| f.write(" cmd.header.command);\n") |
| f.write(" EXPECT_EQ(sizeof(cmd) +\n") |
| f.write(" RoundSizeToMultipleOfEntries(cmd.n * 4u),\n") |
| f.write(" cmd.header.size * 4u);\n") |
| f.write(" EXPECT_EQ(static_cast<GLsizei>(base::size(ids)), cmd.n);\n"); |
| f.write(" CheckBytesWrittenMatchesExpectedSize(\n") |
| f.write(" next_cmd, sizeof(cmd) +\n") |
| f.write(" RoundSizeToMultipleOfEntries(base::size(ids) * 4u));\n") |
| f.write(" EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd),\n") |
| f.write(" sizeof(ids)));\n") |
| f.write("}\n") |
| f.write("\n") |
| |
| |
| class GETnHandler(TypeHandler): |
| """Handler for GETn for glGetBooleanv, glGetFloatv, ... type functions.""" |
| |
| def InitFunction(self, func): |
| """Overrriden from TypeHandler.""" |
| TypeHandler.InitFunction(self, func) |
| |
| if func.name == 'GetSynciv': |
| return |
| |
| arg_insert_point = len(func.passthrough_service_doer_args) - 1; |
| func.passthrough_service_doer_args.insert( |
| arg_insert_point, Argument('length', 'GLsizei*')) |
| func.passthrough_service_doer_args.insert( |
| arg_insert_point, Argument('bufsize', 'GLsizei')) |
| |
| def NeedsDataTransferFunction(self, func): |
| """Overriden from TypeHandler.""" |
| return False |
| |
| def WriteServiceImplementation(self, func, f): |
| """Overrriden from TypeHandler.""" |
| self.WriteServiceHandlerFunctionHeader(func, f) |
| if func.IsES31(): |
| return |
| last_arg = func.GetLastOriginalArg() |
| # All except shm_id and shm_offset. |
| all_but_last_args = func.GetCmdArgs()[:-2] |
| for arg in all_but_last_args: |
| arg.WriteGetCode(f) |
| |
| code = """ typedef cmds::%(func_name)s::Result Result; |
| GLsizei num_values = 0; |
| if (!GetNumValuesReturnedForGLGet(pname, &num_values)) { |
| LOCAL_SET_GL_ERROR_INVALID_ENUM(":%(func_name)s", pname, "pname"); |
| return error::kNoError; |
| } |
| uint32_t checked_size = 0; |
| if (!Result::ComputeSize(num_values).AssignIfValid(&checked_size)) { |
| return error::kOutOfBounds; |
| } |
| Result* result = GetSharedMemoryAs<Result*>( |
| c.%(last_arg_name)s_shm_id, c.%(last_arg_name)s_shm_offset, |
| checked_size); |
| %(last_arg_type)s %(last_arg_name)s = result ? result->GetData() : nullptr; |
|