blob: 2ad89edd99c94ae76a8720fe7ce39938f5419136 [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',
Jamie Madill811b6352015-02-09 10:17:09 -050044 'Program',
45 'Query',
46 'Renderbuffer',
Jamie Madill35170f52016-05-25 12:57:38 -040047 'Sampler',
Jamie Madill811b6352015-02-09 10:17:09 -050048 'Shader',
49 'Surface',
50 'Texture',
51 'TransformFeedback',
52 'VertexArray',
53]
54
55h_file_template = """//
Jamie Madill35170f52016-05-25 12:57:38 -040056// Copyright 2016 The ANGLE Project Authors. All rights reserved.
Jamie Madill811b6352015-02-09 10:17:09 -050057// Use of this source code is governed by a BSD-style license that can be
58// found in the LICENSE file.
59//
Jamie Madill35170f52016-05-25 12:57:38 -040060// $TypedImpl.h:
61// Defines the class interface for $TypedImpl, implementing $BaseImpl.
62//
Jamie Madill811b6352015-02-09 10:17:09 -050063
Geoff Langf9a6f082015-01-22 13:32:49 -050064#ifndef LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
65#define LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
Jamie Madill811b6352015-02-09 10:17:09 -050066
67#include "libANGLE/renderer/$BaseImpl.h"
68
69namespace rx
70{
71
72class $TypedImpl : public $BaseImpl
73{
74 public:
75 $TypedImpl($ConstructorParams);
76 ~$TypedImpl() override;
Jamie Madilled58f062015-04-01 14:17:05 -040077$ImplMethodDeclarations$PrivateImplMethodDeclarations};
Jamie Madill811b6352015-02-09 10:17:09 -050078
Jamie Madill35170f52016-05-25 12:57:38 -040079} // namespace rx
Jamie Madill811b6352015-02-09 10:17:09 -050080
Jamie Madill35170f52016-05-25 12:57:38 -040081#endif // LIBANGLE_RENDERER_${RendererNameCaps}_${TypedImplCaps}_H_
Jamie Madill811b6352015-02-09 10:17:09 -050082"""
83
84cpp_file_template = """//
Jamie Madill35170f52016-05-25 12:57:38 -040085// Copyright $Year The ANGLE Project Authors. All rights reserved.
Jamie Madill811b6352015-02-09 10:17:09 -050086// Use of this source code is governed by a BSD-style license that can be
87// found in the LICENSE file.
88//
Jamie Madill35170f52016-05-25 12:57:38 -040089// $TypedImpl.cpp:
90// Implements the class methods for $TypedImpl.
91//
Jamie Madill811b6352015-02-09 10:17:09 -050092
93#include "libANGLE/renderer/$RendererName/$TypedImpl.h"
94
95#include "common/debug.h"
96
97namespace rx
98{
99
Jamie Madill35170f52016-05-25 12:57:38 -0400100$TypedImpl::$TypedImpl($ConstructorParams) : $BaseImpl($BaseContructorArgs)
101{
102}
Jamie Madill811b6352015-02-09 10:17:09 -0500103
104$TypedImpl::~$TypedImpl()
Jamie Madill35170f52016-05-25 12:57:38 -0400105{
Jamie Madill811b6352015-02-09 10:17:09 -0500106}
Jamie Madill35170f52016-05-25 12:57:38 -0400107$ImplMethodDefinitions
108} // namespace rx
Jamie Madill811b6352015-02-09 10:17:09 -0500109"""
110
111def generate_impl_declaration(impl_stub):
112 # ensure the wrapped lines are aligned vertically
113 temp = re.sub(r'\n ', '\n', impl_stub)
114 return temp + ' override;\n'
115
116def generate_impl_definition(impl_stub, typed_impl):
117 function_signature = impl_stub.strip()
118
119 # strip comments
120 function_signature = re.sub(r'\/\/[^\n]*\n', '', function_signature).strip()
121
122 prog = re.compile(r'^(.+[ \*\&])([^ \(\*\&]+\()')
123 return_value = prog.match(function_signature).group(1)
124
125 # ensure the wrapped lines are aligned vertically
126 spaces = ' ' * len(typed_impl)
127 function_signature = re.sub(r'\n ', '\n' + spaces, function_signature)
128
129 # add class scoping
130 function_signature = prog.sub(r'\1' + typed_impl + r'::\2', function_signature)
131 function_signature += '\n'
132
133 return_statement = ''
134 return_type = return_value.strip()
135
136 if return_type != 'void':
137 # specialized return values for Errors, pointers, etc
138 if return_type == 'gl::Error':
139 return_statement = ' return gl::Error(GL_INVALID_OPERATION);\n'
140 elif return_type == 'egl::Error':
141 return_statement = ' return egl::Error(EGL_BAD_ACCESS);\n'
142 elif return_type == 'LinkResult':
143 return_statement = ' return LinkResult(false, gl::Error(GL_INVALID_OPERATION));\n'
Jamie Madill35170f52016-05-25 12:57:38 -0400144 elif re.search(r'\*$', return_type):
Jamie Madill811b6352015-02-09 10:17:09 -0500145 return_statement = ' return static_cast<' + return_type + '>(0);\n'
Jamie Madill35170f52016-05-25 12:57:38 -0400146 elif re.search(r'const ([^ \&]+) \&$', return_type):
147 obj_type = re.search(r'const ([^ \&]+) \&$', return_type).group(1)
148 return_statement = ' static ' + obj_type + ' local;\n' + ' return local;\n'
Jamie Madill811b6352015-02-09 10:17:09 -0500149 else:
150 return_statement = ' return ' + return_type + '();\n'
151
152 body = '{\n' + ' UNIMPLEMENTED();\n' + return_statement +'}\n'
153
154 return '\n' + function_signature + body
155
156def get_constructor_args(constructor):
157 params = re.search(r'\((.*)\)', constructor).group(1)
158 args = ', '.join(re.findall(r'[^\w]?(\w+)(?:\,|$)', params))
159 return params, args
160
Jamie Madill28291c52015-03-16 10:46:54 -0400161def parse_impl_header(base_impl):
Jamie Madill811b6352015-02-09 10:17:09 -0500162 impl_h_file_path = base_impl + '.h'
Jamie Madill811b6352015-02-09 10:17:09 -0500163 impl_h_file = open(impl_h_file_path, 'r')
Jamie Madill811b6352015-02-09 10:17:09 -0500164
165 # extract impl stubs
166 copy = False
167 copy_private = False
168 impl_stubs = ''
169 private_impl_stubs = ''
170 constructor = base_impl + '() {}'
171 for line in impl_h_file:
172 clean_line = line.strip()
173
Jamie Madill28291c52015-03-16 10:46:54 -0400174 match = re.search(r'^(?:explicit )?(' + base_impl + r'\([^\)]*\))', clean_line);
175 if match:
176 constructor = match.group(1)
Jamie Madill811b6352015-02-09 10:17:09 -0500177
178 # begin capture when reading the destructor.
179 # begin capture also in the private scope (a few special cases)
180 # end capture when we reach a non-virtual function, or different scope.
181 if '~' + base_impl in clean_line:
182 copy = True
183 copy_private = False
Jamie Madilled58f062015-04-01 14:17:05 -0400184 elif 'private:' in clean_line:
Jamie Madill811b6352015-02-09 10:17:09 -0500185 copy = False
186 copy_private = True
187 elif ';' in clean_line and ' = 0' not in clean_line:
188 copy = False
189 copy_private = False
190 elif '}' in clean_line or 'protected:' in clean_line or 'private:' in clean_line:
191 copy = False
192 copy_private = False
193 elif copy:
194 impl_stubs += line
195 elif copy_private:
196 private_impl_stubs += line
197
Jamie Madill28291c52015-03-16 10:46:54 -0400198 impl_h_file.close()
199
200 return impl_stubs, private_impl_stubs, constructor
201
Jamie Madill35170f52016-05-25 12:57:38 -0400202def get_base_class(base_impl):
203 impl_h_file_path = base_impl + '.h'
204 with open(impl_h_file_path, 'r') as impl_h_file:
205 for line in impl_h_file:
206 match = re.search(r'^class ' + base_impl + r' : public (\w+)', line)
207 if match:
208 return match.group(1)
209 return False
210
Jamie Madill28291c52015-03-16 10:46:54 -0400211for impl_class in impl_classes:
212
Jamie Madill35170f52016-05-25 12:57:38 -0400213 base_impl = impl_class + 'Impl'
Jamie Madill28291c52015-03-16 10:46:54 -0400214 typed_impl = impl_class + renderer_suffix
215
216 h_file_path = os.path.join(renderer_name, typed_impl + '.h')
217 cpp_file_path = os.path.join(renderer_name, typed_impl + '.cpp')
218
219 h_file = open(h_file_path, 'w')
220 cpp_file = open(cpp_file_path, 'w')
221
222 # extract impl stubs
223 impl_stubs, private_impl_stubs, constructor = parse_impl_header(base_impl)
224
Jamie Madill35170f52016-05-25 12:57:38 -0400225 # Handle base classes, skipping angle::NonCopyable.
226 base_class = get_base_class(base_impl)
227 if base_class and base_class != 'angle':
228 base_impl_stubs, base_private_impl_stubs, base_constructor = parse_impl_header(base_class)
Jamie Madill28291c52015-03-16 10:46:54 -0400229 impl_stubs += base_impl_stubs
230 private_impl_stubs += base_private_impl_stubs
231
Jamie Madill811b6352015-02-09 10:17:09 -0500232 impl_method_declarations = ''
233 impl_method_definitions = ''
234 private_impl_method_declarations = ''
235
236 for impl_stub in impl_stubs.split(' = 0;\n'):
237 # use 'virtual' to identify the strings with functions
238 if 'virtual' in impl_stub:
239 temp = re.sub(r'virtual ', '', impl_stub)
240 impl_method_declarations += generate_impl_declaration(temp)
241 impl_method_definitions += generate_impl_definition(temp, typed_impl)
242
243 for impl_stub in private_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 private_impl_method_declarations += generate_impl_declaration(temp)
248 impl_method_definitions += generate_impl_definition(temp, typed_impl)
249
250 constructor_params, base_constructor_args = get_constructor_args(constructor)
251
Jamie Madilled58f062015-04-01 14:17:05 -0400252 if private_impl_method_declarations:
253 private_impl_method_declarations = "\n private:\n" + private_impl_method_declarations
254
Jamie Madill811b6352015-02-09 10:17:09 -0500255 substitutions = {
256 'BaseImpl': base_impl,
257 'TypedImpl': typed_impl,
258 'TypedImplCaps': typed_impl.upper(),
259 'RendererName': renderer_name,
260 'RendererNameCaps': renderer_name.upper(),
261 'ImplMethodDeclarations': impl_method_declarations,
262 'ImplMethodDefinitions': impl_method_definitions,
263 'ConstructorParams': constructor_params,
264 'BaseContructorArgs': base_constructor_args,
265 'PrivateImplMethodDeclarations': private_impl_method_declarations,
Jamie Madill35170f52016-05-25 12:57:38 -0400266 'Year': datetime.datetime.now().year,
Jamie Madill811b6352015-02-09 10:17:09 -0500267 }
268
269 h_file.write(string.Template(h_file_template).substitute(substitutions))
270 cpp_file.write(string.Template(cpp_file_template).substitute(substitutions))
271
Jamie Madill811b6352015-02-09 10:17:09 -0500272 h_file.close()
273 cpp_file.close()
Jamie Madill35170f52016-05-25 12:57:38 -0400274
275# Print a block of source files to add to the GYP
276print("Generated files:")
277for impl_class in impl_classes:
278 path = "libANGLE/renderer/" + renderer_name + "/" + impl_class + renderer_suffix
279 print('\'' + path + ".cpp\',")
280 print('\'' + path + ".h\',")