summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/dlm/dlm_generated.py
blob: e5468e2b8e3830d9a7a22413fe728d66810a702e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# $Id: dlm_generated.py $
import sys, cPickle, re

sys.path.append( "../glapi_parser" )
import apiutil

# A routine that can create call strings from instance names
def InstanceCallString( params ):
	output = ''
	for index in range(0,len(params)):
		if index > 0:
			output += ", "
		if params[index][0] != '':
			output += 'instance->' + params[index][0]
	return output

def GetPointerType(basetype):
	words = basetype.split()
	if words[0] == 'const':
		words = words[1:]
	if words[-1].endswith('*'):
		words[-1] = words[-1][:-1].strip()
		if words[-1] == '':
			words = words[:-1]
	if words[0] == 'void' or words[0] == 'GLvoid':
		words[0] = 'int'
	return ' '.join(words)


def GetPointerInfo(functionName):
	# We'll keep track of all the parameters that require pointers.
	# They'll require special handling later.
	params = apiutil.Parameters(functionName)
	pointers = []
	pointername=''
	pointerarg=''
	pointertype=''
	pointersize=0
	pointercomment=''

	index = 0
	for (name, type, vecSize) in params:
		# Watch out for the word "const" (which should be ignored)
		# and for types that end in "*" (which are pointers and need
		# special treatment)
		words = type.split()
		if words[-1].endswith('*'):
			pointers.append(index)
		index += 1

	# If any argument was a pointer, we need a special pointer data
	# array.  The pointer data will be stored into this array, and
	# references to the array will be generated as parameters.
	if len(pointers) == 1:
		index = pointers[0]
		pointername = params[index][0]
		pointerarg = pointername + 'Data'
		pointertype = GetPointerType(params[index][1])
		pointersize = params[index][2]
		if pointersize == 0:
			pointersize = "special"
	elif len(pointers) > 1:
		pointerarg = 'data';
		pointertype = GetPointerType(params[pointers[0]][1])
		for index in range(1,len(pointers)):
			if GetPointerType(params[pointers[index]][1]) != pointertype:
				pointertype = 'GLvoid *'

	return (pointers,pointername,pointerarg,pointertype,pointersize,pointercomment)

def wrap_struct(functionName):
	params = apiutil.Parameters(functionName)
	argstring = apiutil.MakeDeclarationString(params)
	extendedArgstring = argstring
	props = apiutil.Properties(functionName)
	if "useclient" in props or "pixelstore" in props:
		extendedArgstring += ", CRClientState *c"

	# We'll keep track of all the parameters that require pointers.
	# They'll require special handling later.
	(pointers, pointername, pointerarg, pointertype, pointersize, pointercomment) = GetPointerInfo(functionName)

	# Start writing the header
	print 'struct instance%s {' % (functionName)
	print '	DLMInstanceList *next;'
	print '	DLMInstanceList *stateNext;'
	print '	int cbInstance;'
	print '	VBoxDLOpCode iVBoxOpCode;'
	print '	void (DLM_APIENTRY *execute)(DLMInstanceList *instance, SPUDispatchTable *dispatchTable);'
	for (name, type, vecSize) in params:
		# Watch out for the word "const" (which should be ignored)
		# and for types that end in "*" (which are pointers and need
		# special treatment)
		words = type.split()
		if words[0] == 'const':
			words = words[1:]
		if words[0] != "void":
			print '	%s %s;' % (' '.join(words), name)

	# If any argument was a pointer, we need a special pointer data
	# array.  The pointer data will be stored into this array, and
	# references to the array will be generated as parameters.
	if len(pointers) == 1:
		if pointersize == None:
			print "	/* Oh no - pointer parameter %s found, but no pointer class specified and can't guess */" % pointername
		else:
			if pointersize == 'special':
				print '	%s %s[1];%s' % (pointertype, pointerarg, pointercomment)
			else:
				print '	%s %s[%s];%s' % (pointertype, pointerarg, pointersize,pointercomment)
	elif len(pointers) > 1:
		print '	%s %s[1];%s' % (pointertype, pointerarg,pointercomment)

	print '};'

	# Pointers only happen with instances
	if len(pointers) > 1 or (len(pointers) == 1 and pointersize == 'special'):
		print 'int crdlm_pointers_%s(struct instance%s *instance, %s);' % (functionName, functionName, extendedArgstring)
		
	# See if the GL function must sometimes allow passthrough even
	# if the display list is open
	if "checklist" in apiutil.ChromiumProps(functionName):
		print 'int crdlm_checklist_%s(%s);' % (functionName, argstring)

	return

def wrap_execute(functionName):

    params = apiutil.Parameters(functionName)
    (pointers, _, pointerarg, _, _, _) = GetPointerInfo(functionName)

    print 'static void execute%s(DLMInstanceList *x, SPUDispatchTable *dispatchTable)' % functionName
    print '{'
    if len(params) > 0:
        print '    struct instance%s *instance = (struct instance%s *)x;' % (functionName, functionName)

    if len(pointers) == 1:
        print '    instance->%s = instance->%s;' % (params[pointers[0]][0], pointerarg)

    print '    if (dispatchTable->%s != NULL)' % (functionName)
    print '        dispatchTable->%s(%s);' % (functionName, InstanceCallString(params))
    print '    else'
    print '        crWarning("DLM warning: execute%s called with NULL dispatch entry");' % (functionName)
    print '}'

# These code snippets isolate the code required to add a given instance
# to the display list correctly.  They are used during generation, to
# generate correct code, and also to create useful utilities.
def AddInstanceToList(pad):
    print '%s/* Add this instance to the current display list. */' % pad
    print '%sinstance->next = NULL;' % pad
    print '%sinstance->stateNext = NULL;' % pad
    print '%sif (!state->currentListInfo->first) {' % pad
    print '%s    state->currentListInfo->first = (DLMInstanceList *)instance;' % pad
    print '%s}' % pad
    print '%selse {' % pad
    print '%s  state->currentListInfo->last->next = (DLMInstanceList *)instance;' % pad
    print '%s}' % pad
    print '%sstate->currentListInfo->last = (DLMInstanceList *)instance;' % pad
    print '%sstate->currentListInfo->numInstances++;' % pad

def AddInstanceToStateList(pad):
    print '%s/* Instances that change state have to be added to the state list as well. */' % pad
    print '%sif (!state->currentListInfo->stateFirst) {' % pad
    print '%s    state->currentListInfo->stateFirst = (DLMInstanceList *)instance;' % pad
    print '%s}' % pad
    print '%selse {' % pad
    print '%s    state->currentListInfo->stateLast->stateNext = (DLMInstanceList *)instance;' % pad
    print '%s}' % pad
    print '%sstate->currentListInfo->stateLast = (DLMInstanceList *)instance;' % pad


# The compile wrapper collects the parameters into a DLMInstanceList
# element, and adds that element to the end of the display list currently
# being compiled.
def wrap_compile(functionName):
    params = apiutil.Parameters(functionName)
    return_type = apiutil.ReturnType(functionName)
    # Make sure the return type is void.  It's nonsensical to compile
    # an element with any other return type.
    if return_type != 'void':
        print '/* Nonsense: DL function %s has a %s return type?!? */' % (functionName, return_type)

    # Define a structure to hold all the parameters.  Note that the
    # top parameters must exactly match the DLMInstanceList structure
    # in include/cr_dlm.h, or everything will break horribly.
    # Start off by getting all the pointer info we could ever use
    # from the parameters
    (pointers, pointername, pointerarg, pointertype, pointersize, pointercomment) = GetPointerInfo(functionName)

    # Finally, the compile wrapper.  This one will diverge strongly
    # depending on whether or not there are pointer parameters. 
    callstring = apiutil.MakeCallString(params)
    argstring = apiutil.MakeDeclarationString(params)
    props = apiutil.Properties(functionName)
    if "useclient" in props or "pixelstore" in props:
        callstring += ", c"
        argstring += ", CRClientState *c"
    print 'void DLM_APIENTRY crDLMCompile%s(%s)' % (functionName, argstring)
    print '{'
    print '    CRDLMContextState *state = CURRENT_STATE();'
    print '    struct instance%s *instance;' % (functionName)

    # The calling SPU is supposed to verify that the element is supposed to be
    # compiled before it is actually compiled; typically, this is done based
    # on whether a glNewList has been executed more recently than a glEndList.
    # But some functions are dual-natured, sometimes being compiled, and sometimes
    # being executed immediately.  We can check for this here.
    if "checklist" in apiutil.ChromiumProps(functionName):
        print '    if (crDLMCheckList%s(%s))' % (functionName, apiutil.MakeCallString(params))
        print '    {'
        print '        crdlm_error(__LINE__, __FILE__, GL_INVALID_OPERATION,'
        print '            "this instance of function %s should not be compiled");' % functionName;
        print '        return;'
        print '    }'

    if len(pointers) > 1 or pointersize == 'special':
        # Pass NULL, to just allocate space
        print '    instance = crCalloc(sizeof(struct instance%s) + crdlm_pointers_%s(NULL, %s));' % (functionName, functionName, callstring)
    else:
        print '    instance = crCalloc(sizeof(struct instance%s));' % (functionName)
    print '    if (!instance)'
    print '    {'
    print '        crdlm_error(__LINE__, __FILE__, GL_OUT_OF_MEMORY,'
    print '            "out of memory adding %s to display list");' % (functionName)
    print '        return;'
    print '    }'

    # Put in the fields that must always exist
    print '    instance->execute = execute%s;' % functionName

    # Apply all the simple (i.e. non-pointer) parameters
    for index in range(len(params)):
        if index not in pointers:
            name = params[index][0]
            print '    instance->%s = %s;' % (name, name)

    # We need to know instance size in bytes in order to save its state later.
    print '    instance->cbInstance = sizeof(struct instance%s);' % functionName

    # Set OPCODE.
    print '    instance->iVBoxOpCode = VBOX_DL_OPCODE_%s;' % functionName

    # If there's a pointer parameter, apply it.
    if len(pointers) == 1:

        print '    if (%s == NULL)' % (params[pointers[0]][0])
        print '        instance->%s = NULL;' % (params[pointers[0]][0])
        print '    else'
        print '        instance->%s = instance->%s;' % (params[pointers[0]][0], pointerarg)

        if pointersize == 'special':
            print '    instance->cbInstance += crdlm_pointers_%s(instance, %s);' % (functionName, callstring)
        else:
            print '    crMemcpy((void *)instance->%s, (void *) %s, %s*sizeof(%s));' % (params[pointers[0]][0], params[pointers[0]][0], pointersize, pointertype)
    elif len(pointers) == 2:
        # this seems to work
        print '    instance->cbInstance += crdlm_pointers_%s(instance, %s);' % (functionName, callstring)
    elif len(pointers) > 2:
        print "#error don't know how to handle pointer parameters for %s" % (functionName)

    # Add the element to the current display list
    AddInstanceToList('    ')
    # If the element is a state-changing element, add it to the current state list
    if apiutil.SetsTrackedState(functionName):
        AddInstanceToStateList('    ')
    print '}'

whichfile=sys.argv[1]
if whichfile == 'headers':
    print """#ifndef _DLM_GENERATED_H
#define _DLM_GENERATED_H

#include <VBoxUhgsmi.h>

/* DO NOT EDIT.  This file is auto-generated by dlm_generated.py. */
"""
else:
    print """#include <stdio.h>
#include "cr_spu.h"
#include "cr_dlm.h"
#include "cr_mem.h"
#include "cr_error.h"
#include "state/cr_statefuncs.h"
#include "dlm.h"
#include "dlm_pointers.h"
#include "dlm_generated.h"

/* DO NOT EDIT.  This file is auto-generated by dlm_generated.py. */
"""

# Add in the "add_to_dl" utility function, which will be used by
# external (i.e. non-generated) functions.  The utility ensures that 
# any external functions that are written for compiling elements
# don't have to be rewritten if the conventions for adding to display
# lists are changed.
print """
void crdlm_add_to_list(
    DLMInstanceList *instance,
    void (*executeFunc)(DLMInstanceList *x, SPUDispatchTable *dispatchTable)"""

if (whichfile == 'headers'):
    print ");"
else:
    print """) {
    CRDLMContextState *state = CURRENT_STATE();
    instance->execute = executeFunc;"""

    # Add in the common code for adding the instance to the display list
    AddInstanceToList("    ")

    print '}'
    print ''

# Now generate the functions that won't use the crdlm_add_to_list utility.
# These all directly add their own instances to the current display list
# themselves, without using the crdlm_add_to_list() function.
keys = apiutil.GetDispatchedFunctions(sys.argv[3]+"/APIspec.txt")
for func_name in keys:
	if apiutil.CanCompile(func_name):
		print "\n/*** %s ***/" % func_name
		# Auto-generate an appropriate DL function.  First, functions
		# that go into the display list but that rely on state will
		# have to have their argument strings expanded, to take pointers 
		# to that appropriate state.
		if whichfile == "headers":
		    wrap_struct(func_name)
		elif not apiutil.FindSpecial("dlm", func_name):
		    wrap_execute(func_name)
		    wrap_compile(func_name)


# Generate mapping between OPCODE and routines to be executed.

if whichfile == "headers":
    # Execute routine prototype needed to add static array of routines.
    print ''
    print 'struct DLMInstanceList;'
    print 'typedef void (*VBoxDLMExecuteFn)(struct DLMInstanceList *instance, SPUDispatchTable *dispatchTable);'
    print ''
    print 'extern VBoxDLMExecuteFn g_VBoxDLMExecuteFns[VBOX_DL_OPCODE_MAX];'
    print ''
else:
    print ''
    print 'VBoxDLMExecuteFn g_VBoxDLMExecuteFns[] = {'

    for func_name in keys:
        if apiutil.CanCompile(func_name) and not apiutil.FindSpecial("dlm", func_name):
            print '    execute%s,' % func_name

    print '};'
    print ''

if whichfile == 'headers':
    print "#endif /* _DLM_GENERATED_H */"