blob: bd3a9b23b3344231dc16ae86aea321fb386f8c8f [file] [log] [blame]
Jamie Madill811b6352015-02-09 10:17:09 -05001#!/usr/bin/python
2#
3# Copyright (c) 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
Jamie Madill35170f52016-05-25 12:57:38 -040018import os, sys, re, string, datetime
Jamie Madill811b6352015-02-09 10:17:09 -050019
20if len(sys.argv) < 3:
Jamie Madill35170f52016-05-25 12:57:38 -040021 print('Usage: ' + sys.argv[0] + ' <renderer dir name> <renderer class suffix>')
22 sys.exit(1)
Jamie Madill811b6352015-02-09 10:17:09 -050023
24renderer_name = sys.argv[1]
25renderer_suffix = sys.argv[2]
26
Jamie Madill35170f52016-05-25 12:57:38 -040027# change to the renderer directory
28os.chdir(os.path.join(os.path.dirname(sys.argv[0]), "..", "src", "libANGLE", "renderer"))
29
Jamie Madill811b6352015-02-09 10:17:09 -050030# ensure subdir exists
31if not os.path.isdir(renderer_name):
32 os.mkdir(renderer_name)
33
34impl_classes = [
35 'Buffer',
36 'Compiler',
Jamie Madill35170f52016-05-25 12:57:38 -040037 'Context',
38 'Device',
Jamie Madill811b6352015-02-09 10:17:09 -050039 'Display',
40 'FenceNV',
41 'FenceSync',
42 'Framebuffer',
Jamie Madill35170f52016-05-25 12:57:38 -040043 'Image',
Geoff Langd08f3b32016-09-23 15:56:30 -040044 'Path',
Jamie Madill811b6352015-02-09 10:17:09 -050045 'Program',
46 'Query',
47 'Renderbuffer',
Jamie Madill35170f52016-05-25 12:57:38 -040048 'Sampler',
Jamie Madill811b6352015-02-09 10:17:09 -050049 'Shader',
50 'Surface',
51 'Texture',
52 'TransformFeedback',
53 'VertexArray',
54]
55
56h_file_template = """//
Jamie Madill35170f52016-05-25 12:57:38 -040057// Copyright 2016 The ANGLE Project Authors. All rights reserved.
Jamie Madill811b6352015-02-09 10:17:09 -050058// Use of this source code is governed by a BSD-style license that can be
59// found in the LICENSE file.
60//
Jamie Madill35170f52016-05-25 12:57:38 -040061// $TypedImpl.h:
62// Defines the class interface for $TypedImpl, implementing $BaseImpl.
63//
Jamie Madill811b6352015-02-09 10:17:09 -050064
Geoff Langf9a6f082015-01-22 13:32:49 -050065#ifndef LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
66#define LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
Jamie Madill811b6352015-02-09 10:17:09 -050067
68#include "libANGLE/renderer/$BaseImpl.h"
69
70namespace rx
71{
72
73class $TypedImpl : public $BaseImpl
74{
75 public:
76 $TypedImpl($ConstructorParams);
77 ~$TypedImpl() override;
Jamie Madilled58f062015-04-01 14:17:05 -040078$ImplMethodDeclarations$PrivateImplMethodDeclarations};
Jamie Madill811b6352015-02-09 10:17:09 -050079
Jamie Madill35170f52016-05-25 12:57:38 -040080} // namespace rx
Jamie Madill811b6352015-02-09 10:17:09 -050081
Jamie Madill35170f52016-05-25 12:57:38 -040082#endif // LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
Jamie Madill811b6352015-02-09 10:17:09 -050083"""
84
85cpp_file_template = """//
Jamie Madill35170f52016-05-25 12:57:38 -040086// Copyright $Year The ANGLE Project Authors. All rights reserved.
Jamie Madill811b6352015-02-09 10:17:09 -050087// Use of this source code is governed by a BSD-style license that can be
88// found in the LICENSE file.
89//
Jamie Madill35170f52016-05-25 12:57:38 -040090// $TypedImpl.cpp:
91// Implements the class methods for $TypedImpl.
92//
Jamie Madill811b6352015-02-09 10:17:09 -050093
94#include "libANGLE/renderer/$RendererName/$TypedImpl.h"
95
96#include "common/debug.h"
97
98namespace rx
99{
100
Jamie Madill35170f52016-05-25 12:57:38 -0400101$TypedImpl::$TypedImpl($ConstructorParams) : $BaseImpl($BaseContructorArgs)
102{
103}
Jamie Madill811b6352015-02-09 10:17:09 -0500104
105$TypedImpl::~$TypedImpl()
Jamie Madill35170f52016-05-25 12:57:38 -0400106{
Jamie Madill811b6352015-02-09 10:17:09 -0500107}
Jamie Madill35170f52016-05-25 12:57:38 -0400108$ImplMethodDefinitions
109} // namespace rx
Jamie Madill811b6352015-02-09 10:17:09 -0500110"""
111
112def generate_impl_declaration(impl_stub):
113 # ensure the wrapped lines are aligned vertically
114 temp = re.sub(r'\n ', '\n', impl_stub)
115 return temp + ' override;\n'
116
117def generate_impl_definition(impl_stub, typed_impl):
118 function_signature = impl_stub.strip()
119
120 # strip comments
121 function_signature = re.sub(r'\/\/[^\n]*\n', '', function_signature).strip()
122
123 prog = re.compile(r'^(.+[ \*\&])([^ \(\*\&]+\()')
124 return_value = prog.match(function_signature).group(1)
125
126 # ensure the wrapped lines are aligned vertically
127 spaces = ' ' * len(typed_impl)
128 function_signature = re.sub(r'\n ', '\n' + spaces, function_signature)
129
130 # add class scoping
131 function_signature = prog.sub(r'\1' + typed_impl + r'::\2', function_signature)
132 function_signature += '\n'
133
134 return_statement = ''
135 return_type = return_value.strip()
136
137 if return_type != 'void':
138 # specialized return values for Errors, pointers, etc
139 if return_type == 'gl::Error':
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500140 return_statement = ' return gl::InvalidOperation();\n'
Jamie Madill811b6352015-02-09 10:17:09 -0500141 elif return_type == 'egl::Error':
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500142 return_statement = ' return egl::EglBadAccess();\n'
Jamie Madill811b6352015-02-09 10:17:09 -0500143 elif return_type == 'LinkResult':
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500144 return_statement = ' return gl::InvalidOperation();\n'
Jamie Madill35170f52016-05-25 12:57:38 -0400145 elif re.search(r'\*$', return_type):
Jamie Madill811b6352015-02-09 10:17:09 -0500146 return_statement = ' return static_cast<' + return_type + '>(0);\n'
Jamie Madill35170f52016-05-25 12:57:38 -0400147 elif re.search(r'const ([^ \&]+) \&$', return_type):
148 obj_type = re.search(r'const ([^ \&]+) \&$', return_type).group(1)
149 return_statement = ' static ' + obj_type + ' local;\n' + ' return local;\n'
Jamie Madill811b6352015-02-09 10:17:09 -0500150 else:
151 return_statement = ' return ' + return_type + '();\n'
152
153 body = '{\n' + ' UNIMPLEMENTED();\n' + return_statement +'}\n'
154
155 return '\n' + function_signature + body
156
157def get_constructor_args(constructor):
158 params = re.search(r'\((.*)\)', constructor).group(1)
159 args = ', '.join(re.findall(r'[^\w]?(\w+)(?:\,|$)', params))
160 return params, args
161
Jamie Madill28291c52015-03-16 10:46:54 -0400162def parse_impl_header(base_impl):
Jamie Madill811b6352015-02-09 10:17:09 -0500163 impl_h_file_path = base_impl + '.h'
Jamie Madill811b6352015-02-09 10:17:09 -0500164 impl_h_file = open(impl_h_file_path, 'r')
Jamie Madill811b6352015-02-09 10:17:09 -0500165
166 # extract impl stubs
167 copy = False
168 copy_private = False
169 impl_stubs = ''
170 private_impl_stubs = ''
171 constructor = base_impl + '() {}'
172 for line in impl_h_file:
173 clean_line = line.strip()
174
Jamie Madill28291c52015-03-16 10:46:54 -0400175 match = re.search(r'^(?:explicit )?(' + base_impl + r'\([^\)]*\))', clean_line);
176 if match:
177 constructor = match.group(1)
Jamie Madill811b6352015-02-09 10:17:09 -0500178
179 # begin capture when reading the destructor.
180 # begin capture also in the private scope (a few special cases)
181 # end capture when we reach a non-virtual function, or different scope.
182 if '~' + base_impl in clean_line:
183 copy = True
184 copy_private = False
Jamie Madilled58f062015-04-01 14:17:05 -0400185 elif 'private:' in clean_line:
Jamie Madill811b6352015-02-09 10:17:09 -0500186 copy = False
187 copy_private = True
188 elif ';' in clean_line and ' = 0' not in clean_line:
189 copy = False
190 copy_private = False
191 elif '}' in clean_line or 'protected:' in clean_line or 'private:' in clean_line:
192 copy = False
193 copy_private = False
194 elif copy:
195 impl_stubs += line
196 elif copy_private:
197 private_impl_stubs += line
198
Jamie Madill28291c52015-03-16 10:46:54 -0400199 impl_h_file.close()
200
201 return impl_stubs, private_impl_stubs, constructor
202
Jamie Madill35170f52016-05-25 12:57:38 -0400203def get_base_class(base_impl):
204 impl_h_file_path = base_impl + '.h'
205 with open(impl_h_file_path, 'r') as impl_h_file:
206 for line in impl_h_file:
207 match = re.search(r'^class ' + base_impl + r' : public (\w+)', line)
208 if match:
209 return match.group(1)
210 return False
211
Jamie Madill28291c52015-03-16 10:46:54 -0400212for impl_class in impl_classes:
213
Jamie Madill35170f52016-05-25 12:57:38 -0400214 base_impl = impl_class + 'Impl'
Jamie Madill28291c52015-03-16 10:46:54 -0400215 typed_impl = impl_class + renderer_suffix
216
217 h_file_path = os.path.join(renderer_name, typed_impl + '.h')
218 cpp_file_path = os.path.join(renderer_name, typed_impl + '.cpp')
219
220 h_file = open(h_file_path, 'w')
221 cpp_file = open(cpp_file_path, 'w')
222
223 # extract impl stubs
224 impl_stubs, private_impl_stubs, constructor = parse_impl_header(base_impl)
225
Jamie Madill35170f52016-05-25 12:57:38 -0400226 # Handle base classes, skipping angle::NonCopyable.
227 base_class = get_base_class(base_impl)
228 if base_class and base_class != 'angle':
229 base_impl_stubs, base_private_impl_stubs, base_constructor = parse_impl_header(base_class)
Jamie Madill28291c52015-03-16 10:46:54 -0400230 impl_stubs += base_impl_stubs
231 private_impl_stubs += base_private_impl_stubs
232
Jamie Madill811b6352015-02-09 10:17:09 -0500233 impl_method_declarations = ''
234 impl_method_definitions = ''
235 private_impl_method_declarations = ''
236
237 for impl_stub in impl_stubs.split(' = 0;\n'):
238 # use 'virtual' to identify the strings with functions
239 if 'virtual' in impl_stub:
240 temp = re.sub(r'virtual ', '', impl_stub)
241 impl_method_declarations += generate_impl_declaration(temp)
242 impl_method_definitions += generate_impl_definition(temp, typed_impl)
243
244 for impl_stub in private_impl_stubs.split(' = 0;\n'):
245 # use 'virtual' to identify the strings with functions
246 if 'virtual' in impl_stub:
247 temp = re.sub(r'virtual ', '', impl_stub)
248 private_impl_method_declarations += generate_impl_declaration(temp)
249 impl_method_definitions += generate_impl_definition(temp, typed_impl)
250
251 constructor_params, base_constructor_args = get_constructor_args(constructor)
252
Jamie Madilled58f062015-04-01 14:17:05 -0400253 if private_impl_method_declarations:
254 private_impl_method_declarations = "\n private:\n" + private_impl_method_declarations
255
Jamie Madill811b6352015-02-09 10:17:09 -0500256 substitutions = {
257 'BaseImpl': base_impl,
258 'TypedImpl': typed_impl,
259 'TypedImplCaps': typed_impl.upper(),
260 'RendererName': renderer_name,
261 'RendererNameCaps': renderer_name.upper(),
262 'ImplMethodDeclarations': impl_method_declarations,
263 'ImplMethodDefinitions': impl_method_definitions,
264 'ConstructorParams': constructor_params,
265 'BaseContructorArgs': base_constructor_args,
266 'PrivateImplMethodDeclarations': private_impl_method_declarations,
Jamie Madill35170f52016-05-25 12:57:38 -0400267 'Year': datetime.datetime.now().year,
Jamie Madill811b6352015-02-09 10:17:09 -0500268 }
269
270 h_file.write(string.Template(h_file_template).substitute(substitutions))
271 cpp_file.write(string.Template(cpp_file_template).substitute(substitutions))
272
Jamie Madill811b6352015-02-09 10:17:09 -0500273 h_file.close()
274 cpp_file.close()
Jamie Madill35170f52016-05-25 12:57:38 -0400275
276# Print a block of source files to add to the GYP
277print("Generated files:")
278for impl_class in impl_classes:
279 path = "libANGLE/renderer/" + renderer_name + "/" + impl_class + renderer_suffix
280 print('\'' + path + ".cpp\',")
281 print('\'' + path + ".h\',")