1#!/usr/bin/python2 2# 3# Copyright 2015 The ANGLE Project Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# generate_new_renderer.py: 8# Utility script to generate stubs for a new Renderer class. 9# Usage: generate_new_renderer.py <renderer name> <renderer suffix> 10# Renderer name is the folder for the renderer subdirectory 11# Renderer suffix is the abbreviation to append after the class names. 12# 13# The script is fairly robust but may not work for all new methods or 14# other unexpected features. It expects that abstract methods are all 15# grouped after the public destructor or after the private 16# DISALLOW_COPY_AND_ASSIGN macro. 17 18import os, sys, re, string, datetime 19 20if len(sys.argv) < 3: 21 print('Usage: ' + sys.argv[0] + ' <renderer dir name> <renderer class suffix>') 22 sys.exit(1) 23 24renderer_name = sys.argv[1] 25renderer_suffix = sys.argv[2] 26 27# change to the renderer directory 28os.chdir(os.path.join(os.path.dirname(sys.argv[0]), "..", "src", "libANGLE", "renderer")) 29 30# ensure subdir exists 31if not os.path.isdir(renderer_name): 32 os.mkdir(renderer_name) 33 34impl_classes = [ 35 'Buffer', 36 'Compiler', 37 'Context', 38 'Device', 39 'Display', 40 'FenceNV', 41 'FenceSync', 42 'Framebuffer', 43 'Image', 44 'Path', 45 'Program', 46 'Query', 47 'Renderbuffer', 48 'Sampler', 49 'Shader', 50 'Surface', 51 'Texture', 52 'TransformFeedback', 53 'VertexArray', 54] 55 56h_file_template = """// 57// Copyright 2016 The ANGLE Project Authors. All rights reserved. 58// Use of this source code is governed by a BSD-style license that can be 59// found in the LICENSE file. 60// 61// $TypedImpl.h: 62// Defines the class interface for $TypedImpl, implementing $BaseImpl. 63// 64 65#ifndef LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_ 66#define LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_ 67 68#include "libANGLE/renderer/$BaseImpl.h" 69 70namespace rx 71{ 72 73class $TypedImpl : public $BaseImpl 74{ 75 public: 76 $TypedImpl($ConstructorParams); 77 ~$TypedImpl() override; 78$ImplMethodDeclarations$PrivateImplMethodDeclarations}; 79 80} // namespace rx 81 82#endif // LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_ 83""" 84 85cpp_file_template = """// 86// Copyright $Year The ANGLE Project Authors. All rights reserved. 87// Use of this source code is governed by a BSD-style license that can be 88// found in the LICENSE file. 89// 90// $TypedImpl.cpp: 91// Implements the class methods for $TypedImpl. 92// 93 94#include "libANGLE/renderer/$RendererName/$TypedImpl.h" 95 96#include "common/debug.h" 97 98namespace rx 99{ 100 101$TypedImpl::$TypedImpl($ConstructorParams) : $BaseImpl($BaseContructorArgs) 102{ 103} 104 105$TypedImpl::~$TypedImpl() 106{ 107} 108$ImplMethodDefinitions 109} // namespace rx 110""" 111 112 113def generate_impl_declaration(impl_stub): 114 # ensure the wrapped lines are aligned vertically 115 temp = re.sub(r'\n ', '\n', impl_stub) 116 return temp + ' override;\n' 117 118 119def generate_impl_definition(impl_stub, typed_impl): 120 function_signature = impl_stub.strip() 121 122 # strip comments 123 function_signature = re.sub(r'\/\/[^\n]*\n', '', function_signature).strip() 124 125 prog = re.compile(r'^(.+[ \*\&])([^ \(\*\&]+\()') 126 return_value = prog.match(function_signature).group(1) 127 128 # ensure the wrapped lines are aligned vertically 129 spaces = ' ' * len(typed_impl) 130 function_signature = re.sub(r'\n ', '\n' + spaces, function_signature) 131 132 # add class scoping 133 function_signature = prog.sub(r'\1' + typed_impl + r'::\2', function_signature) 134 function_signature += '\n' 135 136 return_statement = '' 137 return_type = return_value.strip() 138 139 if return_type != 'void': 140 # specialized return values for Errors, pointers, etc 141 if return_type == 'gl::Error': 142 return_statement = ' return gl::InvalidOperation();\n' 143 elif return_type == 'egl::Error': 144 return_statement = ' return egl::EglBadAccess();\n' 145 elif return_type == 'LinkResult': 146 return_statement = ' return gl::InvalidOperation();\n' 147 elif re.search(r'\*$', return_type): 148 return_statement = ' return static_cast<' + return_type + '>(0);\n' 149 elif re.search(r'const ([^ \&]+) \&$', return_type): 150 obj_type = re.search(r'const ([^ \&]+) \&$', return_type).group(1) 151 return_statement = ' static ' + obj_type + ' local;\n' + ' return local;\n' 152 else: 153 return_statement = ' return ' + return_type + '();\n' 154 155 body = '{\n' + ' UNIMPLEMENTED();\n' + return_statement + '}\n' 156 157 return '\n' + function_signature + body 158 159 160def get_constructor_args(constructor): 161 params = re.search(r'\((.*)\)', constructor).group(1) 162 args = ', '.join(re.findall(r'[^\w]?(\w+)(?:\,|$)', params)) 163 return params, args 164 165 166def parse_impl_header(base_impl): 167 impl_h_file_path = base_impl + '.h' 168 impl_h_file = open(impl_h_file_path, 'r') 169 170 # extract impl stubs 171 copy = False 172 copy_private = False 173 impl_stubs = '' 174 private_impl_stubs = '' 175 constructor = base_impl + '() {}' 176 for line in impl_h_file: 177 clean_line = line.strip() 178 179 match = re.search(r'^(?:explicit )?(' + base_impl + r'\([^\)]*\))', clean_line) 180 if match: 181 constructor = match.group(1) 182 183 # begin capture when reading the destructor. 184 # begin capture also in the private scope (a few special cases) 185 # end capture when we reach a non-virtual function, or different scope. 186 if '~' + base_impl in clean_line: 187 copy = True 188 copy_private = False 189 elif 'private:' in clean_line: 190 copy = False 191 copy_private = True 192 elif ';' in clean_line and ' = 0' not in clean_line: 193 copy = False 194 copy_private = False 195 elif '}' in clean_line or 'protected:' in clean_line or 'private:' in clean_line: 196 copy = False 197 copy_private = False 198 elif copy: 199 impl_stubs += line 200 elif copy_private: 201 private_impl_stubs += line 202 203 impl_h_file.close() 204 205 return impl_stubs, private_impl_stubs, constructor 206 207 208def get_base_class(base_impl): 209 impl_h_file_path = base_impl + '.h' 210 with open(impl_h_file_path, 'r') as impl_h_file: 211 for line in impl_h_file: 212 match = re.search(r'^class ' + base_impl + r' : public (\w+)', line) 213 if match: 214 return match.group(1) 215 return False 216 217 218for impl_class in impl_classes: 219 220 base_impl = impl_class + 'Impl' 221 typed_impl = impl_class + renderer_suffix 222 223 h_file_path = os.path.join(renderer_name, typed_impl + '.h') 224 cpp_file_path = os.path.join(renderer_name, typed_impl + '.cpp') 225 226 h_file = open(h_file_path, 'w') 227 cpp_file = open(cpp_file_path, 'w') 228 229 # extract impl stubs 230 impl_stubs, private_impl_stubs, constructor = parse_impl_header(base_impl) 231 232 # Handle base classes, skipping angle::NonCopyable. 233 base_class = get_base_class(base_impl) 234 if base_class and base_class != 'angle': 235 base_impl_stubs, base_private_impl_stubs, base_constructor = parse_impl_header(base_class) 236 impl_stubs += base_impl_stubs 237 private_impl_stubs += base_private_impl_stubs 238 239 impl_method_declarations = '' 240 impl_method_definitions = '' 241 private_impl_method_declarations = '' 242 243 for impl_stub in impl_stubs.split(' = 0;\n'): 244 # use 'virtual' to identify the strings with functions 245 if 'virtual' in impl_stub: 246 temp = re.sub(r'virtual ', '', impl_stub) 247 impl_method_declarations += generate_impl_declaration(temp) 248 impl_method_definitions += generate_impl_definition(temp, typed_impl) 249 250 for impl_stub in private_impl_stubs.split(' = 0;\n'): 251 # use 'virtual' to identify the strings with functions 252 if 'virtual' in impl_stub: 253 temp = re.sub(r'virtual ', '', impl_stub) 254 private_impl_method_declarations += generate_impl_declaration(temp) 255 impl_method_definitions += generate_impl_definition(temp, typed_impl) 256 257 constructor_params, base_constructor_args = get_constructor_args(constructor) 258 259 if private_impl_method_declarations: 260 private_impl_method_declarations = "\n private:\n" + private_impl_method_declarations 261 262 substitutions = { 263 'BaseImpl': base_impl, 264 'TypedImpl': typed_impl, 265 'TypedImplCaps': typed_impl.upper(), 266 'RendererName': renderer_name, 267 'RendererNameCaps': renderer_name.upper(), 268 'ImplMethodDeclarations': impl_method_declarations, 269 'ImplMethodDefinitions': impl_method_definitions, 270 'ConstructorParams': constructor_params, 271 'BaseContructorArgs': base_constructor_args, 272 'PrivateImplMethodDeclarations': private_impl_method_declarations, 273 'Year': datetime.datetime.now().year, 274 } 275 276 h_file.write(string.Template(h_file_template).substitute(substitutions)) 277 cpp_file.write(string.Template(cpp_file_template).substitute(substitutions)) 278 279 h_file.close() 280 cpp_file.close() 281 282# Print a block of source files to add to the build 283print("Generated files:") 284for impl_class in impl_classes: 285 path = "libANGLE/renderer/" + renderer_name + "/" + impl_class + renderer_suffix 286 print('\'' + path + ".cpp\',") 287 print('\'' + path + ".h\',") 288