blob: 2d96f810d7c5daa5122f2eb0cb29a8945985f3d8 [file] [log] [blame]
# 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, 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:
last_arg = func.GetLastOriginalArg()
all_but_last_arg = func.GetOriginalArgs()[:-1]
for arg in all_but_last_arg:
arg.WriteGetCode(f)
self.WriteGetDataSizeCode(func, f)
last_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, 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, 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, f):
"""Overrriden from TypeHandler."""
# TODO: Move this data to _FUNCTION_INFO?
name = func.name
if name.endswith("Immediate"):
name = name[0:-9]
if name in ['BufferData', 'BufferSubData', 'RasterCHROMIUM']:
f.write(" uint32_t data_size = size;\n")
else:
f.write(
"// uint32_t data_size = 0; // WARNING: compute correct size.\n")
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, f):
"""Overrriden from TypeHandler."""
code = """ uint32_t data_size;
if (!%sSafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
return error::kOutOfBounds;
}
""" % _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(arraysize(ids), &ids[0]);
expected.data[0] = k%(types)sStartId;
expected.data[1] = k%(types)sStartId + 1;
gl_->%(name)s(arraysize(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>(arraysize(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>(arraysize(ids)), cmd.n);\n");
f.write(" CheckBytesWrittenMatchesExpectedSize(\n")
f.write(" next_cmd, sizeof(cmd) +\n")
f.write(" RoundSizeToMultipleOfEntries(arraysize(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(
" GPU_CLIENT_DCHECK(%s != 0);\n" % 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 DELnHa