1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "ApiGen.h"
17 #include "aemu/base/EnumFlags.h"
18 #include "EntryPoint.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include "strUtils.h"
22 #include <errno.h>
23 #include <sys/types.h>
24 
25 /* Define this to 1 to enable support for the 'isLarge' variable flag
26  * that instructs the encoder to send large data buffers by a direct
27  * write through the pipe (i.e. without copying it into a temporary
28  * buffer. This has definite performance benefits when using a QEMU Pipe.
29  *
30  * Set to 0 otherwise.
31  */
32 #define WITH_LARGE_SUPPORT  1
33 
34 // Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned.
35 // This prevents crashes with certain backends (e.g. OSMesa).
36 #define USE_ALIGNED_BUFFERS 1
37 
38 // Set these to 1 if you want to instrument either guest's or host's code for
39 // time-per-call printing.
40 #define INSTRUMENT_TIMING_GUEST 0
41 #define INSTRUMENT_TIMING_HOST 0
42 
43 // Set to 1 to print to logcat for every GL call encoded.
44 #define DLOG_ALL_ENCODES 0
45 
46 // Set to 1 to check GL errors before and after every decoder call.
47 #define DECODER_CHECK_GL_ERRORS 0
48 
findEntryByName(const std::string & name)49 EntryPoint * ApiGen::findEntryByName(const std::string & name)
50 {
51     EntryPoint * entry = NULL;
52 
53     size_t n = this->size();
54     for (size_t i = 0; i < n; i++) {
55         if (at(i).name() == name) {
56             entry = &(at(i));
57             break;
58         }
59     }
60     return entry;
61 }
62 
printHeader(FILE * fp) const63 void ApiGen::printHeader(FILE *fp) const
64 {
65     fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
66     fprintf(fp, "// generated by 'emugen'\n");
67 }
68 
genProcTypes(const std::string & filename,SideType side)69 int ApiGen::genProcTypes(const std::string &filename, SideType side)
70 {
71     FILE *fp = fopen(filename.c_str(), "wt");
72     if (fp == NULL) {
73         perror(filename.c_str());
74         return -1;
75     }
76     printHeader(fp);
77 
78     const char* basename = m_basename.c_str();
79 
80     fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side));
81     fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side));
82     fprintf(fp, "\n\n");
83     fprintf(fp, "\n#include \"%s_types.h\"\n",basename);
84     fprintf(fp, "#ifdef _MSC_VER\n");
85     fprintf(fp, "#include <stdint.h>\n");
86     fprintf(fp, "#endif\n");
87     fprintf(fp, "#ifndef %s_APIENTRY\n",basename);
88     fprintf(fp, "#define %s_APIENTRY \n",basename);
89     fprintf(fp, "#endif\n");
90 
91 
92     for (size_t i = 0; i < size(); i++) {
93         EntryPoint *e = &at(i);
94 
95         fprintf(fp, "typedef ");
96         e->retval().printType(fp);
97         fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
98         if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
99         if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
100 
101         VarsArray & evars = e->vars();
102         size_t n = evars.size();
103 
104         for (size_t j = 0; j < n; j++) {
105             if (!evars[j].isVoid()) {
106                 if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
107                 evars[j].printType(fp);
108             }
109         }
110         fprintf(fp, ");\n");
111 
112         if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
113             fprintf(fp, "typedef ");
114             e->retval().printType(fp);
115             fprintf(fp, " (%s_APIENTRY *%s_dec_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
116 
117             VarsArray & evars = e->vars();
118             size_t n = evars.size();
119 
120             for (size_t j = 0; j < n; j++) {
121                 if (!evars[j].isVoid()) {
122                     if (j != 0) fprintf(fp, ", ");
123                     evars[j].printType(fp);
124                 }
125             }
126             fprintf(fp, ");\n");
127         }
128     }
129     fprintf(fp, "\n\n#endif\n");
130     return 0;
131 }
132 
genFuncTable(const std::string & filename,SideType side)133 int ApiGen::genFuncTable(const std::string &filename, SideType side)
134 {
135     FILE *fp = fopen(filename.c_str(), "wt");
136     if (fp == NULL) {
137         perror(filename.c_str());
138         return -1;
139     }
140     printHeader(fp);
141 
142     fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
143     fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
144     fprintf(fp, "\n\n");
145     fprintf(fp, "static const struct _%s_funcs_by_name {\n", m_basename.c_str());
146     fprintf(fp,
147             "\tconst char *name;\n" \
148             "\tvoid *proc;\n" \
149             "} %s_funcs_by_name[] = {\n", m_basename.c_str());
150 
151 
152     for (size_t i = 0; i < size(); i++) {
153         EntryPoint *e = &at(i);
154         if (e->notApi()) continue;
155         fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str());
156     }
157     fprintf(fp, "};\n");
158     fprintf(fp, "static const int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n",
159             m_basename.c_str(), m_basename.c_str(), m_basename.c_str());
160     fprintf(fp, "\n\n#endif\n");
161     return 0;
162 }
163 
genContext(const std::string & filename,SideType side)164 int ApiGen::genContext(const std::string & filename, SideType side)
165 {
166     FILE *fp = fopen(filename.c_str(), "wt");
167     if (fp == NULL) {
168         perror(filename.c_str());
169         return -1;
170     }
171     printHeader(fp);
172 
173     fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
174     fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
175 
176     fprintf(fp, "\n#include \"%s_%s_proc.h\"\n",
177             m_basename.c_str(),
178             side == CLIENT_SIDE ? "client" : "server");
179     fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
180 
181     StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
182     for (size_t i = 0; i < contextHeaders.size(); i++) {
183         fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
184     }
185     fprintf(fp, "\n");
186 
187     fprintf(fp, "\nstruct %s_%s_context_t {\n\n",
188             m_basename.c_str(), sideString(side));
189 
190     // API entry points
191     for (size_t i = 0; i < size(); i++) {
192         EntryPoint *e = &at(i);
193         if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
194             fprintf(fp, "\t%s_dec_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
195             fprintf(fp, "\t%s_%s_proc_t %s_dec;\n", e->name().c_str(), sideString(side), e->name().c_str());
196         } else {
197             fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
198         }
199     }
200 
201     // virtual destructor
202     fprintf(fp, "\tvirtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
203     // accessor
204     if (side == CLIENT_SIDE || side == WRAPPER_SIDE) {
205         fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
206                 m_basename.c_str(), sideString(side));
207         fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
208     }
209 
210     // init function
211     fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
212 
213     //client site set error virtual func
214     if (side == CLIENT_SIDE) {
215         fprintf(fp, "\tvirtual void setError(unsigned int  error){ (void)error; }\n");
216         fprintf(fp, "\tvirtual unsigned int getError(){ return 0; }\n");
217     }
218 
219     fprintf(fp, "};\n");
220 
221     fprintf(fp, "\n#endif\n");
222     fclose(fp);
223     return 0;
224 }
225 
genEntryPoints(const std::string & filename,SideType side)226 int ApiGen::genEntryPoints(const std::string & filename, SideType side)
227 {
228 
229     if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
230         fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
231         return -999;
232     }
233 
234 
235     FILE *fp = fopen(filename.c_str(), "wt");
236     if (fp == NULL) {
237         perror(filename.c_str());
238         return errno;
239     }
240 
241     printHeader(fp);
242     fprintf(fp, "#include <stdio.h>\n");
243     fprintf(fp, "#include <stdlib.h>\n");
244     fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side));
245     fprintf(fp, "\n");
246 
247     fprintf(fp, "extern \"C\" {\n");
248 
249     for (size_t i = 0; i < size(); i++) {
250         fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
251     }
252     fprintf(fp, "};\n\n");
253 
254     fprintf(fp, "#ifndef GET_CONTEXT\n");
255     fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
256             m_basename.c_str(), sideString(side));
257 
258     fprintf(fp,
259             "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n",
260             m_basename.c_str(), sideString(side));
261     fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext()\n",
262                 m_basename.c_str(), sideString(side));
263     fprintf(fp, "#endif\n\n");
264 
265 
266     for (size_t i = 0; i < size(); i++) {
267         EntryPoint *e = &at(i);
268         e->print(fp);
269         fprintf(fp, "{\n");
270         fprintf(fp, "\tGET_CONTEXT;\n");
271 
272         bool shouldReturn = !e->retval().isVoid();
273         bool shouldCallWithContext = (side == CLIENT_SIDE);
274         //param check
275         if (shouldCallWithContext) {
276             for (size_t j=0; j<e->vars().size(); j++) {
277                 if (e->vars()[j].paramCheckExpression() != "")
278                     fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str());
279             }
280         }
281         fprintf(fp, "\t%sctx->%s(%s",
282                 shouldReturn ? "return " : "",
283                 e->name().c_str(),
284                 shouldCallWithContext ? "ctx" : "");
285         size_t nvars = e->vars().size();
286 
287         for (size_t j = 0; j < nvars; j++) {
288             if (!e->vars()[j].isVoid()) {
289                 fprintf(fp, "%s %s",
290                         j != 0 || shouldCallWithContext ? "," : "",
291                         e->vars()[j].name().c_str());
292             }
293         }
294         fprintf(fp, ");\n");
295         fprintf(fp, "}\n\n");
296     }
297     fclose(fp);
298     return 0;
299 }
300 
301 
genOpcodes(const std::string & filename)302 int ApiGen::genOpcodes(const std::string &filename)
303 {
304     FILE *fp = fopen(filename.c_str(), "wt");
305     if (fp == NULL) {
306         perror(filename.c_str());
307         return errno;
308     }
309 
310     printHeader(fp);
311     fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
312     fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
313     for (size_t i = 0; i < size(); i++) {
314         fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
315     }
316     fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
317     fprintf(fp,"\n\n#endif\n");
318     fclose(fp);
319     return 0;
320 
321 }
genAttributesTemplate(const std::string & filename)322 int ApiGen::genAttributesTemplate(const std::string &filename )
323 {
324     FILE *fp = fopen(filename.c_str(), "wt");
325     if (fp == NULL) {
326         perror(filename.c_str());
327         return -1;
328     }
329 
330     for (size_t i = 0; i < size(); i++) {
331         if (at(i).hasPointers()) {
332             fprintf(fp, "#");
333             at(i).print(fp);
334             fprintf(fp, "%s\n\n", at(i).name().c_str());
335         }
336     }
337     fclose(fp);
338     return 0;
339 }
340 
genEncoderHeader(const std::string & filename)341 int ApiGen::genEncoderHeader(const std::string &filename)
342 {
343     FILE *fp = fopen(filename.c_str(), "wt");
344     if (fp == NULL) {
345         perror(filename.c_str());
346         return -1;
347     }
348 
349     printHeader(fp);
350     std::string classname = m_basename + "_encoder_context_t";
351 
352     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
353     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
354 
355     fprintf(fp, "#include \"gfxstream/guest/ChecksumCalculator.h\"\n");
356     fprintf(fp, "#include \"gfxstream/guest/IOStream.h\"\n");
357 
358     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
359 
360     for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
361         fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
362     }
363     fprintf(fp, "\n");
364 
365     // fprintf(fp, "namespace gfxstream {\n");
366 
367     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
368             classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
369     fprintf(fp, "\tgfxstream::guest::IOStream *m_stream;\n");
370     fprintf(fp, "\tgfxstream::guest::ChecksumCalculator *m_checksumCalculator;\n\n");
371 
372     fprintf(fp, "\t%s(gfxstream::guest::IOStream *stream, gfxstream::guest::ChecksumCalculator *checksumCalculator);\n", classname.c_str());
373     fprintf(fp, "\tvirtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }\n");
374     fprintf(fp, "};\n\n");
375 
376     // fprintf(fp, "}  // namespace gfxstream\n");
377 
378     fprintf(fp, "#endif  // GUARD_%s\n", classname.c_str());
379 
380     fclose(fp);
381     return 0;
382 }
383 
384 // Format the byte length expression for a given variable into a user-provided buffer
385 // If the variable type is not a pointer, this is simply its size as a decimal constant
386 // If the variable is a pointer, this will be an expression provided by the .attrib file
387 // through the 'len' attribute.
388 //
389 // Returns 1 if the variable is a pointer, 0 otherwise
390 //
391 enum class EncodingSizeFlags {
392     None = 0,
393     DmaPtrOnly = 1,
394     ExcludeOut = 2,
395     UseExistingVar = 4,
396 };
397 
getVarEncodingSizeExpression(Var & var,EntryPoint * e,char * buff,size_t bufflen,EncodingSizeFlags flags)398 static int getVarEncodingSizeExpression(
399         Var& var, EntryPoint* e, char* buff, size_t bufflen,
400         EncodingSizeFlags flags)
401 {
402     if (!var.isPointer()) {
403         snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
404         return 0;
405     }
406 
407     if ((flags & EncodingSizeFlags::DmaPtrOnly) != 0) {
408         snprintf(buff, bufflen, "8");
409     } else if ((flags & EncodingSizeFlags::ExcludeOut) != 0 &&
410             !(var.pointerDir() & Var::POINTER_IN)) {
411         snprintf(buff, bufflen, "0");
412     } else if ((flags & EncodingSizeFlags::UseExistingVar) != 0) {
413         snprintf(buff, bufflen, "__size_%s", var.name().c_str());
414     } else {
415         const char* lenExpr = var.lenExpression().c_str();
416         const char* varname = var.name().c_str();
417         if (e != NULL && lenExpr[0] == '\0') {
418             fprintf(stderr, "%s: data len is undefined for '%s'\n",
419                     e->name().c_str(), varname);
420         }
421         if (var.nullAllowed()) {
422             snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
423         } else {
424             snprintf(buff, bufflen, "%s", lenExpr);
425         }
426     }
427     return 1;
428 }
429 
writeVarEncodingSize(Var & var,bool excludeOutVars,FILE * fp)430 static int writeVarEncodingSize(Var& var, bool excludeOutVars, FILE* fp)
431 {
432     int ret = 0;
433     if (!var.isPointer()) {
434         fprintf(fp, "%u", (unsigned int) var.type()->bytes());
435     } else {
436         ret = 1;
437         if (var.isDMA()) {
438             fprintf(fp, "8");
439             return ret;
440         }
441 
442         if (excludeOutVars && !(var.pointerDir() & Var::POINTER_IN)) {
443             fprintf(fp, "0");
444         } else {
445             fprintf(fp, "__size_%s", var.name().c_str());
446         }
447     }
448     return ret;
449 }
450 
writeVarEncodingExpression(Var & var,FILE * fp)451 static void writeVarEncodingExpression(Var& var, FILE* fp)
452 {
453     const char* varname = var.name().c_str();
454 
455     if (var.isPointer()) {
456         // encode a pointer header
457         if (var.isDMA()) {
458             fprintf(fp, "\t*(uint64_t *)(ptr) = ctx->lockAndWriteDma(%s, __size_%s); ptr += 8;\n", varname, varname);
459         } else {
460             fprintf(fp, "\tmemcpy(ptr, &__size_%s, 4); ptr += 4;\n", varname);
461 
462             Var::PointerDir dir = var.pointerDir();
463             if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
464                 if (var.nullAllowed()) {
465                     fprintf(fp, "\tif (%s != NULL) ", varname);
466                 } else {
467                     fprintf(fp, "\t");
468                 }
469 
470                 if (var.packExpression().size() != 0) {
471                     fprintf(fp, "%s;", var.packExpression().c_str());
472                 } else {
473                     fprintf(fp, "memcpy(ptr, %s, __size_%s);",
474                             varname, varname);
475                 }
476 
477                 fprintf(fp, "ptr += __size_%s;\n", varname);
478             }
479         }
480     } else {
481         // encode a non pointer variable
482         if (!var.isVoid()) {
483             fprintf(fp, "\t\tmemcpy(ptr, &%s, %u); ptr += %u;\n",
484                     varname,
485                     (unsigned) var.type()->bytes(),
486                     (unsigned) var.type()->bytes());
487         }
488     }
489 }
490 
491 #if WITH_LARGE_SUPPORT
writeVarLargeEncodingExpression(Var & var,FILE * fp)492 static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
493 {
494     const char* varname = var.name().c_str();
495 
496     fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
497     fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname);
498     if (var.nullAllowed()) {
499         fprintf(fp, "\tif (%s != NULL) {\n", varname);
500     }
501     if (var.writeExpression() != "") {
502         fprintf(fp, "%s", var.writeExpression().c_str());
503     } else {
504         if (var.guestPackExpression() != "") {
505             fprintf(fp, "\t\t%s;\n", var.guestPackExpression().c_str());
506         } else {
507             fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname);
508         }
509         fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname);
510     }
511     if (var.nullAllowed()) fprintf(fp, "\t}\n");
512 }
513 #endif /* WITH_LARGE_SUPPORT */
514 
writeEncodingChecksumValidatorOnReturn(const char * funcName,FILE * fp)515 static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) {
516     fprintf(fp, "\tif (useChecksum) {\n"
517                 "\t\tunsigned char *checksumBufPtr = NULL;\n"
518                 "\t\tunsigned char checksumBuf[gfxstream::guest::ChecksumCalculator::kMaxChecksumSize];\n"
519                 "\t\tif (checksumSize > 0) checksumBufPtr = &checksumBuf[0];\n"
520                 "\t\tstream->readback(checksumBufPtr, checksumSize);\n"
521                 "\t\tif (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {\n"
522                 "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n"
523                 "\t\t\tabort();\n"
524                 "\t\t}\n"
525                 "\t}\n",
526             funcName
527     );
528 }
529 
addGuestTimePrinting(const EntryPoint * e,bool hasTimeBeforeReadback,FILE * fp)530 static void addGuestTimePrinting(const EntryPoint* e, bool hasTimeBeforeReadback,
531                                  FILE* fp) {
532 #if INSTRUMENT_TIMING_GUEST
533     fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
534     fprintf(fp, "\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
535     if (hasTimeBeforeReadback) {
536         fprintf(fp, "\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
537         fprintf(fp, "\tALOGW(\"%s: %%ld (%%ld) us\\n\", timeDiff, timeDiff2);\n", e->name().c_str());
538     } else {
539         fprintf(fp, "\tALOGW(\"%s: %%ld us\\n\", timeDiff);\n", e->name().c_str());
540     }
541 #endif
542 }
543 
addEncoderDebugLog(const EntryPoint * e,FILE * fp)544 static void addEncoderDebugLog(const EntryPoint* e, FILE* fp) {
545     fprintf(fp, "\tENCODER_DEBUG_LOG(\"%s(", e->name().c_str());
546 
547     const VarsArray& vars = e->vars();
548     for (size_t i = 0; i < vars.size(); i++) {
549         const Var& var = vars[i];
550         if (i != 0) {
551             fprintf(fp, ", ");
552         }
553         fprintf(fp, "%s:%s", var.name().c_str(), var.type()->printFormat().c_str());
554     }
555 
556     fprintf(fp, ")\"");
557     for (size_t i = 0; i < vars.size(); i++) {
558         const Var& var = vars[i];
559         fprintf(fp, ", %s", var.name().c_str());
560     }
561 
562     fprintf(fp, ");\n");
563 }
564 
genEncoderImpl(const std::string & filename)565 int ApiGen::genEncoderImpl(const std::string &filename)
566 {
567     FILE *fp = fopen(filename.c_str(), "wt");
568     if (fp == NULL) {
569         perror(filename.c_str());
570         return -1;
571     }
572 
573     printHeader(fp);
574     fprintf(fp, "\n\n");
575     fprintf(fp, "#include <string.h>\n");
576     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
577     fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
578     fprintf(fp, "#include <vector>\n\n");
579     fprintf(fp, "#include <stdio.h>\n\n");
580     fprintf(fp, "#include \"aemu/base/Tracing.h\"\n\n");
581     fprintf(fp, "#include \"EncoderDebug.h\"\n\n");
582 
583     // fprintf(fp, "namespace gfxstream {\n\n");
584     fprintf(fp, "using gfxstream::guest::ChecksumCalculator;\n\n");
585     fprintf(fp, "using gfxstream::guest::IOStream;\n\n");
586     fprintf(fp, "namespace {\n\n");
587 
588     // unsupport printout
589     fprintf(fp,
590             "void enc_unsupported()\n"
591             "{\n"
592             "\tALOGE(\"Function is unsupported\\n\");\n"
593             "}\n\n");
594 
595     // entry points;
596     std::string classname = m_basename + "_encoder_context_t";
597 
598     size_t n = size();
599     for (size_t i = 0; i < n; i++) {
600         EntryPoint *e = &at(i);
601 
602         if (e->unsupported()) continue;
603 
604         e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
605         fprintf(fp, "{\n");
606 
607         addEncoderDebugLog(e, fp);
608 
609         fprintf(fp, "\tAEMU_SCOPED_TRACE(\"%s encode\");\n", e->name().c_str());
610 
611 #if INSTRUMENT_TIMING_GUEST
612         fprintf(fp, "\tstruct timespec ts0, ts1;\n");
613         fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
614 #endif
615 
616 //      fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
617         fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
618                 classname.c_str(),
619                 classname.c_str());
620         fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n"
621                     "\tgfxstream::guest::ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n"
622                     "\tbool useChecksum = checksumCalculator->getVersion() > 0;\n\n");
623         VarsArray & evars = e->vars();
624         size_t  maxvars = evars.size();
625         size_t  j;
626 
627         char    buff[256];
628 
629         // Define the __size_XXX variables that contain the size of data
630         // associated with pointers.
631         for (j = 0; j < maxvars; j++) {
632             Var& var = evars[j];
633 
634             if (!var.isPointer())
635                 continue;
636 
637             const char* varname = var.name().c_str();
638             fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
639 
640             getVarEncodingSizeExpression(var, e, buff, sizeof(buff),
641                                          EncodingSizeFlags::None);
642             fprintf(fp, "%s;\n", buff);
643         }
644 
645         bool hasLargeFields = false;
646 #if WITH_LARGE_SUPPORT
647         // We need to take care of 'isLarge' variable in a special way
648         // Anything before an isLarge variable can be packed into a single
649         // buffer, which is then commited. Each isLarge variable is a pointer
650         // to data that can be written to directly through the pipe, which
651         // will be instant when using a QEMU pipe
652 
653         size_t  nvars   = 0;
654         size_t  npointers = 0;
655 
656         // First, compute the total size, 8 bytes for the opcode + payload size (without checksum)
657         fprintf(fp, "\t unsigned char *ptr;\n");
658         fprintf(fp, "\t unsigned char *buf;\n");
659         fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");
660 
661         for (j = 0; j < maxvars; j++) {
662             fprintf(fp, " + ");
663             npointers += writeVarEncodingSize(evars[j], true, fp);
664         }
665         if (npointers > 0) {
666             fprintf(fp, " + %zu*4", npointers);
667         }
668         fprintf(fp, ";\n");
669 
670         // Then, size of the checksum string
671         fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
672 
673         // And, size of the whole thing
674         fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
675 
676         // We need to divide the packet into fragments. Each fragment contains
677         // either copied arguments to a temporary buffer, or direct writes for
678         // large variables.
679         //
680         // The first fragment must also contain the opcode+payload_size+checksum_size
681         //
682         nvars = 0;
683         while (nvars < maxvars || maxvars == 0) {
684 
685             // Skip over non-large fields
686             for (j = nvars; j < maxvars; j++) {
687                 if (evars[j].isLarge())
688                     break;
689             }
690 
691             // Write a fragment if needed.
692             if (nvars == 0 || j > nvars) {
693                 const char* plus = "";
694 
695                 if (nvars == 0 && j == maxvars) {
696                     // Simple shortcut for the common case where we don't have large variables;
697                     fprintf(fp, "\tbuf = stream->alloc(totalSize);\n");
698 
699                 } else {
700                     hasLargeFields = true;
701                     // allocate buffer from the stream until the first large variable
702                     fprintf(fp, "\tbuf = stream->alloc(");
703                     plus = "";
704 
705                     if (nvars == 0) {
706                         fprintf(fp,"8"); plus = " + ";
707                     }
708                     if (j > nvars) {
709                         npointers = 0;
710                         for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
711                             fprintf(fp, "%s", plus); plus = " + ";
712                             npointers += writeVarEncodingSize(evars[j], false, fp);
713                         }
714                         if (npointers > 0) {
715                             fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
716                         }
717                     }
718                     fprintf(fp,");\n");
719                 }
720                 fprintf(fp, "\tptr = buf;\n");
721 
722                 // encode packet header if needed.
723                 if (nvars == 0) {
724                     fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
725                     fprintf(fp, "\tmemcpy(ptr, &totalSize, 4);  ptr += 4;\n\n");
726                 }
727 
728                 if (maxvars == 0) {
729                     fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
730                     break;
731                 }
732 
733                 // encode non-large fields in this fragment
734                 for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
735                     writeVarEncodingExpression(evars[j],fp);
736                 }
737 
738                 fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
739                 // Ensure the fragment is commited if it is followed by a large variable
740                 if (j < maxvars) {
741                     fprintf(fp, "\tstream->flush();\n");
742                 }
743             }
744 
745             // If we have one or more large variables, write them directly.
746             // As size + data
747             for ( ; j < maxvars && evars[j].isLarge(); j++) {
748                 writeVarLargeEncodingExpression(evars[j], fp);
749             }
750 
751             nvars = j;
752         }
753 
754 #else /* !WITH_LARGE_SUPPORT */
755         size_t nvars = evars.size();
756         size_t npointers = 0;
757         fprintf(fp, "\tunsigned char *ptr;\n");
758         fprintf(fp, "\tunsigned char *buf;\n");
759         fprintf(fp, "\tconst size_t sizeWithoutChecksum = 8");
760         for (size_t j = 0; j < nvars; j++) {
761             npointers += getVarEncodingSizeExpression(
762                     evars[j], e, buff, sizeof(buff),
763                     (evars[j].isDMA() ? EncodingSizeFlags::DmaPtrOnly
764                                       : EncodingSizeFlags::None) |
765                             EncodingSizeFlags::UseExistingVar |
766                             EncodingSizeFlags::ExcludeOut);
767             fprintf(fp, " + %s", buff);
768         }
769         fprintf(fp, " + %u * 4;\n", (unsigned int)npointers);
770         // Size of checksum
771         fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
772         // Size of the whole thing
773         fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
774 
775         // allocate buffer from the stream;
776         fprintf(fp, "\tptr = buf = stream->alloc(totalSize);\n\n");
777 
778         // encode into the stream;
779         fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str());
780         fprintf(fp, "\tmemcpy(ptr, &totalSize, 4);  ptr += 4;\n\n");
781 
782         // out variables
783         for (size_t j = 0; j < nvars; j++) {
784             writeVarEncodingExpression(evars[j], fp);
785         }
786 
787         fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr - buf);\n");
788 #endif /* !WITH_LARGE_SUPPORT */
789 
790         // checksum
791         if (hasLargeFields) {
792             fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n");
793             fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n");
794         } else {
795             fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n");
796         }
797 
798         // in variables;
799         bool hasTimeBeforeReadback = false;
800         bool hasReadbackChecksum = false;
801         for (size_t j = 0; j < nvars; j++) {
802             if (evars[j].isPointer()) {
803                 Var::PointerDir dir = evars[j].pointerDir();
804                 if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
805                     const char* varname = evars[j].name().c_str();
806                     const char* indent = "\t";
807 
808 #if INSTRUMENT_TIMING_GUEST
809                     if (!hasTimeBeforeReadback) {
810                         hasTimeBeforeReadback = true;
811                         // Let's flush the stream before measuring the time.
812                         fprintf(fp, "\tstream->flush();\n");
813                         fprintf(fp, "\tstruct timespec ts2;\n");
814                         fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
815                     }
816 #endif
817                     if (evars[j].nullAllowed()) {
818                         fprintf(fp, "\tif (%s != NULL) {\n",varname);
819                         indent = "\t\t";
820                     }
821 
822                     if (evars[j].guestUnpackExpression() != "") {
823                         fprintf(fp, "%s%s;\n", indent, evars[j].guestUnpackExpression().c_str());
824                     } else {
825                         if (evars[j].isDMA()) {
826                             fprintf(fp, "%s// Skip readback for var %s as it's DMA\n", indent, varname);
827                         } else {
828                             fprintf(fp, "%sstream->readback(%s, __size_%s);\n",
829                                     indent, varname, varname);
830                         }
831                     }
832                     if (evars[j].isDMA()) {
833                         fprintf(fp, "%s// Skip checksum for var %s as it's DMA\n", indent, varname);
834                     } else {
835                         fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n",
836                                 indent, varname, varname);
837                     }
838                     if (evars[j].nullAllowed()) {
839                         fprintf(fp, "\t}\n");
840                     }
841                     hasReadbackChecksum = true;
842                 }
843             }
844         }
845 //XXX       fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str());
846 
847         // todo - return value for pointers
848         if (e->retval().isPointer()) {
849             fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
850                     e->name().c_str());
851             if (e->flushOnEncode()) {
852                 fprintf(fp, "\tstream->flush();\n");
853             }
854             addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
855             fprintf(fp, "\t return NULL;\n");
856         } else if (e->retval().type()->name() != "void") {
857 #if INSTRUMENT_TIMING_GUEST
858             if (!hasTimeBeforeReadback) {
859                 hasTimeBeforeReadback = true;
860                 fprintf(fp, "\tstream->flush();\n");
861                 fprintf(fp, "\tstruct timespec ts2;\n");
862                 fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
863             }
864 #endif
865 
866             fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
867             fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes());
868             fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n",
869                     (unsigned) e->retval().type()->bytes());
870             writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
871             addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
872             fprintf(fp, "\treturn retval;\n");
873         } else {
874             if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n");
875             if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
876             addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
877         }
878         fprintf(fp, "}\n\n");
879     }
880 
881     fprintf(fp, "}  // namespace\n\n");
882 
883     // constructor
884     fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str());
885     fprintf(fp, "\tm_stream = stream;\n");
886     fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\n\n");
887 
888     for (size_t i = 0; i < n; i++) {
889         EntryPoint *e = &at(i);
890         if (e->unsupported()) {
891             fprintf(fp,
892                     "\tthis->%s = (%s_%s_proc_t) &enc_unsupported;\n",
893                     e->name().c_str(),
894                     e->name().c_str(),
895                     sideString(CLIENT_SIDE));
896         } else {
897             fprintf(fp,
898                     "\tthis->%s = &%s_enc;\n",
899                     e->name().c_str(),
900                     e->name().c_str());
901         }
902     }
903     fprintf(fp, "}\n\n");
904 
905     // fprintf(fp, "} // namespace gfxstream\n\n");
906 
907     fclose(fp);
908     return 0;
909 }
910 
911 
genDecoderHeader(const std::string & filename)912 int ApiGen::genDecoderHeader(const std::string &filename)
913 {
914     FILE *fp = fopen(filename.c_str(), "wt");
915     if (fp == NULL) {
916         perror(filename.c_str());
917         return -1;
918     }
919 
920     printHeader(fp);
921     std::string classname = m_basename + "_decoder_context_t";
922 
923     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
924     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
925 
926     fprintf(fp, "#include \"render-utils/IOStream.h\"\n");
927     fprintf(fp, "#include \"ChecksumCalculator.h\"\n");
928     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
929 #if INSTRUMENT_TIMING_HOST
930     fprintf(fp, "#include \"time.h\"\n");
931 #endif
932 
933     for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
934         fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
935     }
936     fprintf(fp, "\n");
937 
938     fprintf(fp, "namespace gfxstream {\n\n");
939 
940     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
941             classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
942     fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream, ChecksumCalculator* checksumCalc);\n");
943     fprintf(fp, "\n};\n\n");
944 
945     fprintf(fp, "}  // namespace gfxstream\n\n");
946 
947     fprintf(fp, "#endif  // GUARD_%s\n", classname.c_str());
948 
949     fclose(fp);
950     return 0;
951 }
952 
genContextImpl(const std::string & filename,SideType side)953 int ApiGen::genContextImpl(const std::string &filename, SideType side)
954 {
955     FILE *fp = fopen(filename.c_str(), "wt");
956     if (fp == NULL) {
957         perror(filename.c_str());
958         return -1;
959     }
960     printHeader(fp);
961 
962     std::string classname = m_basename + "_" + sideString(side) + "_context_t";
963     size_t n = size();
964     fprintf(fp, "\n\n#include <string.h>\n");
965     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
966     fprintf(fp, "#include <stdio.h>\n\n");
967 
968     fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
969     for (size_t i = 0; i < n; i++) {
970         EntryPoint *e = &at(i);
971         if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
972             fprintf(fp, "\t%s = (%s_dec_%s_proc_t) getProc(\"%s\", userData);\n",
973                     e->name().c_str(),
974                     e->name().c_str(),
975                     sideString(side),
976                     e->name().c_str());
977         } else {
978             fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n",
979                     e->name().c_str(),
980                     e->name().c_str(),
981                     sideString(side),
982                     e->name().c_str());
983         }
984     }
985     fprintf(fp, "\treturn 0;\n");
986     fprintf(fp, "}\n\n");
987     fclose(fp);
988     return 0;
989 }
990 
genDecoderImpl(const std::string & filename)991 int ApiGen::genDecoderImpl(const std::string &filename)
992 {
993     FILE *fp = fopen(filename.c_str(), "wt");
994     if (fp == NULL) {
995         perror(filename.c_str());
996         return -1;
997     }
998 
999     printHeader(fp);
1000 
1001     std::string classname = m_basename + "_decoder_context_t";
1002 
1003     size_t n = size();
1004 
1005     bool changesChecksum = false;
1006     for (size_t i = 0; i < size(); ++i) {
1007         const EntryPoint& ep = at(i);
1008         if (ep.name().find("SelectChecksum") != std::string::npos) {
1009             changesChecksum = true;
1010             break;
1011         }
1012     }
1013 
1014     fprintf(fp, "\n\n#include <string.h>\n");
1015     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
1016     fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
1017     fprintf(fp, "#include \"ProtocolUtils.h\"\n\n");
1018     fprintf(fp, "#include \"ChecksumCalculatorThreadInfo.h\"\n\n");
1019     fprintf(fp, "#include \"host-common/logging.h\"\n\n");
1020     fprintf(fp, "#include <stdio.h>\n\n");
1021 
1022     fprintf(fp, "namespace gfxstream {\n\n");
1023 
1024     fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
1025 
1026     fprintf(fp,
1027 #if DECODER_CHECK_GL_ERRORS
1028             "#define CHECK_GL_ERRORS\n"
1029 #endif
1030             "#ifdef CHECK_GL_ERRORS\n"
1031             "#  define SET_LASTCALL(name)  sprintf(lastCall, #name)\n"
1032             "#else\n"
1033             "#  define SET_LASTCALL(name)\n"
1034             "#endif\n");
1035 
1036     // helper templates
1037 
1038     // decoder switch;
1039     fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream, ChecksumCalculator* checksumCalc) {\n", classname.c_str());
1040     fprintf(fp,
1041 "\tif (len < 8) return 0;\n\
1042 #ifdef CHECK_GL_ERRORS\n\
1043 \tchar lastCall[256] = {0};\n\
1044 #endif\n\
1045 \tunsigned char *ptr = (unsigned char *)buf;\n\
1046 \tconst unsigned char* const end = (const unsigned char*)buf + len;\n");
1047     if (!changesChecksum) {
1048         fprintf(fp,
1049 R"(    const size_t checksumSize = checksumCalc->checksumByteSize();
1050     const bool useChecksum = checksumSize > 0;
1051 )");
1052     }
1053     fprintf(fp,
1054 "\twhile (end - ptr >= 8) {\n\
1055 \t\tuint32_t opcode = *(uint32_t *)ptr;\n\
1056 \t\tuint32_t packetLen = *(uint32_t *)(ptr + 4);\n\
1057 \t\tif (end - ptr < packetLen) return ptr - (unsigned char*)buf;\n");
1058     if (changesChecksum) {
1059         fprintf(fp,
1060 R"(        // Do this on every iteration, as some commands may change the checksum
1061         // calculation parameters.
1062         const size_t checksumSize = checksumCalc->checksumByteSize();
1063         const bool useChecksum = checksumSize > 0;
1064 )");
1065     }
1066     fprintf(fp, "\t\tswitch(opcode) {\n");
1067 
1068     for (size_t f = 0; f < n; f++) {
1069         enum Pass_t {
1070             PASS_FIRST = 0,
1071             PASS_VariableDeclarations = PASS_FIRST,
1072             PASS_Protocol,
1073             PASS_TmpBuffAlloc,
1074             PASS_MemAlloc,
1075             PASS_DebugPrint,
1076             PASS_FunctionCall,
1077             PASS_FlushOutput,
1078             PASS_Epilog,
1079             PASS_LAST };
1080         EntryPoint *e = &(*this)[f];
1081 
1082         // construct a printout string;
1083         std::string printString;
1084         for (size_t i = 0; i < e->vars().size(); i++) {
1085             Var *v = &e->vars()[i];
1086             printString +=  v->name() + ":";
1087             if (!v->isVoid())  printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
1088         }
1089 
1090         // TODO - add for return value;
1091         fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());
1092         fprintf(fp, "\t\t\tandroid::base::beginTrace(\"%s decode\");\n", e->name().c_str());
1093 
1094 #if INSTRUMENT_TIMING_HOST
1095         fprintf(fp, "\t\t\tstruct timespec ts0, ts1, ts2;\n");
1096         fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
1097 #endif
1098         bool totalTmpBuffExist = false;
1099         std::string totalTmpBuffOffset = "0";
1100         std::string *tmpBufOffset = new std::string[e->vars().size()];
1101 
1102         // construct retval type string
1103         std::string retvalType;
1104         if (!e->retval().isVoid()) {
1105             retvalType = e->retval().type()->name();
1106         }
1107 
1108         for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) {
1109 
1110 #if INSTRUMENT_TIMING_HOST
1111             if (pass == PASS_FunctionCall) {
1112                 fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
1113             }
1114 #endif
1115             if (pass == PASS_FunctionCall &&
1116                 !e->retval().isVoid() &&
1117                 !e->retval().isPointer()) {
1118                 fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
1119                         totalTmpBuffOffset.c_str());
1120             }
1121 
1122             if (pass == PASS_FunctionCall) {
1123                 if (e->customDecoder() && !e->notApi()) {
1124                     fprintf(fp, "\t\t\tthis->%s_dec(", e->hostApiName().c_str());
1125                 } else {
1126                     fprintf(fp, "\t\t\tthis->%s(", e->hostApiName().c_str());
1127                 }
1128                 if (e->customDecoder()) {
1129                     fprintf(fp, "this"); // add a context to the call
1130                 }
1131             } else if (pass == PASS_DebugPrint) {
1132                 if (strstr(m_basename.c_str(), "gl")) {
1133                     fprintf(fp, "\t\t\t#ifdef CHECK_GL_ERRORS\n");
1134                     fprintf(fp, "\t\t\tGLint err = this->glGetError();\n");
1135                     fprintf(fp, "\t\t\tif (err) fprintf(stderr, \"%s Error (pre-call): 0x%%X before %s\\n\", err);\n",
1136                             m_basename.c_str(), e->name().c_str());
1137                     fprintf(fp, "\t\t\t#endif\n");
1138                 }
1139 
1140                 fprintf(fp,
1141                         "\t\t\tDECODER_DEBUG_LOG(\"%s(%%p): %s(%s)\", stream",
1142                         m_basename.c_str(),
1143                         e->name().c_str(),
1144                         printString.c_str());
1145                 if (e->vars().size() > 0 && !e->vars()[0].isVoid()) {
1146                     fprintf(fp, ", ");
1147                 }
1148             }
1149 
1150             std::string varoffset = "8"; // skip the header
1151             VarsArray & evars = e->vars();
1152             // allocate memory for out pointers;
1153             for (size_t j = 0; j < evars.size(); j++) {
1154                 Var *v = & evars[j];
1155                 if (v->isVoid()) {
1156                     continue;
1157                 }
1158                 const char* var_name = v->name().c_str();
1159                 const char* var_type_name = v->type()->name().c_str();
1160                 const unsigned var_type_bytes = v->type()->bytes();
1161 
1162                 if ((pass == PASS_FunctionCall) &&
1163                     (j != 0 || e->customDecoder())) {
1164                     fprintf(fp, ", ");
1165                 }
1166                 if (pass == PASS_DebugPrint && j != 0) {
1167                     fprintf(fp, ", ");
1168                 }
1169 
1170                 if (v->isPointer() && v->isDMA()) {
1171                     if (pass == PASS_VariableDeclarations) {
1172                         fprintf(fp,
1173                                 "\t\t\tuint64_t var_%s_guest_paddr = Unpack<uint64_t,uint64_t>(ptr + %s);\n"
1174                                 "\t\t\t%s var_%s = stream->getDmaForReading(var_%s_guest_paddr);\n",
1175                                 var_name,
1176                                 varoffset.c_str(),
1177                                 var_type_name,
1178                                 var_name,
1179                                 var_name);
1180                     }
1181                     if (pass == PASS_FunctionCall ||
1182                         pass == PASS_DebugPrint) {
1183                         fprintf(fp, "var_%s", var_name);
1184                     }
1185                     varoffset += " + 8";
1186                 }
1187 
1188                 if (!v->isPointer()) {
1189                     if (pass == PASS_VariableDeclarations) {
1190                         fprintf(fp,
1191                                 "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n",
1192                                 var_type_name,
1193                                 var_name,
1194                                 var_type_name,
1195                                 var_type_bytes * 8U,
1196                                 varoffset.c_str());
1197                     }
1198 
1199                     if (pass == PASS_FunctionCall ||
1200                         pass == PASS_DebugPrint) {
1201                         fprintf(fp, "var_%s", var_name);
1202                     }
1203                     varoffset += " + " + toString(var_type_bytes);
1204                     continue;
1205                 }
1206 
1207                 if (pass == PASS_VariableDeclarations) {
1208                     fprintf(fp,
1209                             "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n",
1210                             var_name,
1211                             varoffset.c_str());
1212                 }
1213 
1214                 if (!v->isDMA()) {
1215                     if (v->pointerDir() & Var::POINTER_IN) {
1216                         if (pass == PASS_VariableDeclarations) {
1217     #if USE_ALIGNED_BUFFERS
1218                             fprintf(fp,
1219                                     "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n",
1220                                     var_name,
1221                                     varoffset.c_str(),
1222                                     var_name);
1223                             if (v->unpackExpression().size() > 0) {
1224                                 fprintf(fp,
1225                                     "\t\t\tvoid* inptr_%s_unpacked;\n"
1226                                     "\t\t\t%s;\n",
1227                                     var_name,
1228                                     v->unpackExpression().c_str());
1229                             }
1230 
1231                         }
1232                         if (pass == PASS_FunctionCall &&
1233                             v->pointerDir() == Var::POINTER_IN) {
1234                             if (v->nullAllowed()) {
1235                                 fprintf(fp,
1236                                         "size_%s == 0 ? nullptr : (%s)(inptr_%s.get())",
1237                                         var_name,
1238                                         var_type_name,
1239                                         var_name);
1240                             } else {
1241                                 if (v->unpackExpression().size() > 0) {
1242                                     fprintf(fp,
1243                                             "(%s)(inptr_%s_unpacked)",
1244                                             var_type_name,
1245                                             var_name);
1246                                 } else {
1247                                     fprintf(fp,
1248                                             "(%s)(inptr_%s.get())",
1249                                             var_type_name,
1250                                             var_name);
1251                                 }
1252                             }
1253                         } else if (pass == PASS_DebugPrint &&
1254                                    v->pointerDir() == Var::POINTER_IN) {
1255                             fprintf(fp,
1256                                     "(%s)(inptr_%s.get()), size_%s",
1257                                     var_type_name,
1258                                     var_name,
1259                                     var_name);
1260                         }
1261     #else  // !USE_ALIGNED_BUFFERS
1262                             fprintf(fp,
1263                                     "unsigned char *inptr_%s = (ptr + %s + 4);\n",
1264                                     var_name,
1265                                     varoffset.c_str());
1266                         }
1267                         if (pass == PASS_FunctionCall &&
1268                             v->pointerDir() == Var::POINTER_IN) {
1269                             if (v->nullAllowed()) {
1270                                 fprintf(fp,
1271                                         "size_%s == 0 ? NULL : (%s)(inptr_%s)",
1272                                         var_name,
1273                                         var_type_name,
1274                                         var_name);
1275                             } else {
1276                                 fprintf(fp,
1277                                         "(%s)(inptr_%s)",
1278                                         var_type_name,
1279                                         var_name);
1280                             }
1281                         } else if (pass == PASS_DebugPrint &&
1282                                    v->pointerDir() == Var::POINTER_IN) {
1283                             fprintf(fp,
1284                                     "(%s)(inptr_%s), size_%s",
1285                                     var_type_name,
1286                                     var_name,
1287                                     var_name);
1288                         }
1289     #endif  // !USE_ALIGNED_BUFFERS
1290                         varoffset += " + 4 + size_";
1291                         varoffset += var_name;
1292                     }
1293                     if (v->pointerDir() & Var::POINTER_OUT)  { // out pointer;
1294                         if (pass == PASS_TmpBuffAlloc) {
1295                             if (!totalTmpBuffExist) {
1296                                 fprintf(fp,
1297                                         "\t\t\tsize_t totalTmpSize = size_%s;\n",
1298                                         var_name);
1299                             } else {
1300                                 fprintf(fp,
1301                                         "\t\t\ttotalTmpSize += size_%s;\n",
1302                                         var_name);
1303                             }
1304                             tmpBufOffset[j] = totalTmpBuffOffset;
1305                             totalTmpBuffOffset += " + size_";
1306                             totalTmpBuffOffset += var_name;
1307                             totalTmpBuffExist = true;
1308                         } else if (pass == PASS_MemAlloc) {
1309     #if USE_ALIGNED_BUFFERS
1310                             fprintf(fp,
1311                                     "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n",
1312                                     var_name,
1313                                     tmpBufOffset[j].c_str(),
1314                                     var_name);
1315                             // If both input and output variable, initialize with the input.
1316                             if (v->pointerDir() == Var::POINTER_INOUT) {
1317                                 fprintf(fp,
1318                                         "\t\t\tmemcpy(outptr_%s.get(), inptr_%s.get(), size_%s);\n",
1319                                         var_name,
1320                                         var_name,
1321                                         var_name);
1322                             }
1323 
1324                             if (v->hostPackExpression() != "") {
1325                                 fprintf(fp, "\t\t\tvoid* forPacking_%s = nullptr;\n", var_name);
1326                             }
1327                             if (v->hostPackTmpAllocExpression() != "") {
1328                                 fprintf(fp, "\t\t\t%s;\n", v->hostPackTmpAllocExpression().c_str());
1329                             }
1330                         } else if (pass == PASS_FunctionCall) {
1331                             if (v->hostPackExpression() != "") {
1332                                 fprintf(fp,
1333                                         "(%s)(forPacking_%s)",
1334                                         var_type_name,
1335                                         var_name);
1336                             } else {
1337                                 if (v->nullAllowed()) {
1338                                     fprintf(fp,
1339                                             "size_%s == 0 ? nullptr : (%s)(outptr_%s.get())",
1340                                             var_name,
1341                                             var_type_name,
1342                                             var_name);
1343                                 } else {
1344                                     fprintf(fp,
1345                                             "(%s)(outptr_%s.get())",
1346                                             var_type_name,
1347                                             var_name);
1348                                 }
1349                             }
1350                         } else if (pass == PASS_DebugPrint) {
1351                             fprintf(fp,
1352                                     "(%s)(outptr_%s.get()), size_%s",
1353                                     var_type_name,
1354                                     var_name,
1355                                     var_name);
1356                         }
1357                         if (pass == PASS_FlushOutput) {
1358                             if (v->hostPackExpression() != "") {
1359                                 fprintf(fp,
1360                                         "\t\t\tif (size_%s) {\n"
1361                                         "\t\t\t%s; }\n",
1362                                         var_name,
1363                                         v->hostPackExpression().c_str());
1364                             }
1365                             fprintf(fp,
1366                                     "\t\t\toutptr_%s.flush();\n",
1367                                     var_name);
1368                         }
1369     #else  // !USE_ALIGNED_BUFFERS
1370                             fprintf(fp,
1371                                     "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n",
1372                                     var_name,
1373                                     tmpBufOffset[j].c_str());
1374                             fprintf(fp,
1375                                     "\t\t\tmemset(outptr_%s, 0, %s);\n",
1376                                     var_name,
1377                                     toString(v->type()->bytes()).c_str());
1378                         } else if (pass == PASS_FunctionCall) {
1379                             if (v->nullAllowed()) {
1380                                 fprintf(fp,
1381                                         "size_%s == 0 ? NULL : (%s)(outptr_%s)",
1382                                         var_name,
1383                                         var_type_name,
1384                                         var_name);
1385                             } else {
1386                                 fprintf(fp,
1387                                         "(%s)(outptr_%s)",
1388                                         var_type_name,
1389                                         var_name);
1390                             }
1391                         } else if (pass == PASS_DebugPrint) {
1392                             fprintf(fp,
1393                                     "(%s)(outptr_%s), size_%s",
1394                                     var_type_name,
1395                                     var_name,
1396                                     varoffset.c_str());
1397                         }
1398     #endif  // !USE_ALIGNED_BUFFERS
1399                     if (v->pointerDir() == Var::POINTER_OUT) {
1400                         varoffset += " + 4";
1401                     }
1402                     }
1403                 }
1404             }
1405 
1406             if (pass == PASS_Protocol) {
1407                 fprintf(fp,
1408                         "\t\t\tif (useChecksum) {\n"
1409                         "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, %s, "
1410                         "ptr + %s, checksumSize,"
1411                         "\n\t\t\t\t\t\"%s::decode,"
1412                         " OP_%s: GL checksumCalculator failure\\n\");\n"
1413                         "\t\t\t}\n",
1414                         varoffset.c_str(),
1415                         varoffset.c_str(),
1416                         classname.c_str(),
1417                         e->name().c_str()
1418                         );
1419 
1420                 varoffset += " + 4";
1421             }
1422 
1423             if (pass == PASS_FunctionCall ||
1424                 pass == PASS_DebugPrint) {
1425                 fprintf(fp, ");\n");
1426 
1427                 if (pass == PASS_FunctionCall) {
1428                     // unlock all dma buffers that have been passed
1429                     for (size_t j = 0; j < evars.size(); j++) {
1430                         Var *v = & evars[j];
1431                         if (v->isVoid()) {
1432                             continue;
1433                         }
1434                         const char* var_name = v->name().c_str();
1435                         if (v->isDMA()) {
1436                             fprintf(fp,
1437                                     "\t\t\tstream->unlockDma(var_%s_guest_paddr);\n",
1438                                     var_name);
1439                         }
1440                     }
1441                 }
1442             }
1443 
1444             if (pass == PASS_TmpBuffAlloc) {
1445                 if (!e->retval().isVoid() && !e->retval().isPointer()) {
1446                     if (!totalTmpBuffExist)
1447                         fprintf(fp,
1448                                 "\t\t\tsize_t totalTmpSize = sizeof(%s);\n",
1449                                 retvalType.c_str());
1450                     else
1451                         fprintf(fp,
1452                                 "\t\t\ttotalTmpSize += sizeof(%s);\n",
1453                                 retvalType.c_str());
1454 
1455                     totalTmpBuffExist = true;
1456                 }
1457                 if (totalTmpBuffExist) {
1458                     fprintf(fp,
1459                             "\t\t\ttotalTmpSize += checksumSize;\n"
1460                             "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
1461                 }
1462             }
1463 
1464             if (pass == PASS_Epilog) {
1465                 // send back out pointers data as well as retval
1466                 if (totalTmpBuffExist) {
1467                     fprintf(fp,
1468                             "\t\t\tif (useChecksum) {\n"
1469                             "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, "
1470                             "&tmpBuf[0], totalTmpSize - checksumSize, "
1471                             "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n"
1472                             "\t\t\t}\n"
1473                             "\t\t\tstream->flush();\n");
1474                 }
1475             }
1476         } // pass;
1477 
1478 #if INSTRUMENT_TIMING_HOST
1479         fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
1480         fprintf(fp, "\t\t\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
1481         fprintf(fp, "\t\t\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
1482         fprintf(fp, "\t\t\tprintf(\"(timing) %%4ld.%%06ld %s: %%ld (%%ld) us\\n\", "
1483                     "ts1.tv_sec, ts1.tv_nsec/1000, timeDiff, timeDiff2);\n", e->name().c_str());
1484 #endif
1485         fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());
1486         fprintf(fp, "\t\t\tandroid::base::endTrace();\n");
1487         fprintf(fp, "\t\t\tbreak;\n");
1488         fprintf(fp, "\t\t}\n");
1489 
1490         delete [] tmpBufOffset;
1491     }
1492     fprintf(fp, "\t\tdefault:\n");
1493     fprintf(fp, "\t\t\treturn ptr - (unsigned char*)buf;\n");
1494     fprintf(fp, "\t\t} //switch\n");
1495     if (strstr(m_basename.c_str(), "gl")) {
1496         fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");
1497         fprintf(fp, "\t\tGLint err = this->glGetError();\n");
1498         fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (post-call): 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
1499         fprintf(fp, "\t\t#endif\n");
1500     }
1501 
1502     fprintf(fp, "\t\tptr += packetLen;\n");
1503     fprintf(fp, "\t} // while\n");
1504     fprintf(fp, "\treturn ptr - (unsigned char*)buf;\n");
1505     fprintf(fp, "}\n");
1506 
1507     fprintf(fp, "}  // namespace gfxstream\n\n");
1508 
1509     fclose(fp);
1510     return 0;
1511 }
1512 
readSpec(const std::string & filename)1513 int ApiGen::readSpec(const std::string & filename)
1514 {
1515     FILE *specfp = fopen(filename.c_str(), "rt");
1516     if (specfp == NULL) {
1517         return -1;
1518     }
1519 
1520     char line[1000];
1521     unsigned int lc = 0;
1522     while (fgets(line, sizeof(line), specfp) != NULL) {
1523         lc++;
1524         EntryPoint ref;
1525         if (ref.parse(lc, std::string(line))) {
1526             push_back(ref);
1527             updateMaxEntryPointsParams(ref.vars().size());
1528         }
1529     }
1530     fclose(specfp);
1531     return 0;
1532 }
1533 
readAttributes(const std::string & attribFilename)1534 int ApiGen::readAttributes(const std::string & attribFilename)
1535 {
1536     enum { ST_NAME, ST_ATT } state;
1537 
1538     FILE *fp = fopen(attribFilename.c_str(), "rt");
1539     if (fp == NULL) {
1540         perror(attribFilename.c_str());
1541         return -1;
1542     }
1543     char buf[1000];
1544 
1545     state = ST_NAME;
1546     EntryPoint *currentEntry = NULL;
1547     size_t lc = 0;
1548     bool globalAttributes = false;
1549     while (fgets(buf, sizeof(buf), fp) != NULL) {
1550         lc++;
1551         std::string line(buf);
1552         if (line.size() == 0) continue; // could that happen?
1553 
1554         if (line.at(0) == '#') continue; // comment
1555 
1556         size_t first = line.find_first_not_of(" \t\n");
1557         if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
1558 
1559         line = trim(line);
1560         if (line.size() == 0 || line.at(0) == '#') continue;
1561 
1562         switch(state) {
1563         case ST_NAME:
1564             if (line == "GLOBAL") {
1565                 globalAttributes = true;
1566             } else {
1567                 globalAttributes = false;
1568                 currentEntry = findEntryByName(line);
1569                 if (currentEntry == NULL) {
1570                     fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
1571                 }
1572             }
1573             state = ST_ATT;
1574             break;
1575         case ST_ATT:
1576             if (globalAttributes) {
1577                 setGlobalAttribute(line, lc);
1578             } else  if (currentEntry != NULL) {
1579                 currentEntry->setAttribute(line, lc);
1580             }
1581             break;
1582         }
1583     }
1584     return 0;
1585 }
1586 
1587 
setGlobalAttribute(const std::string & line,size_t lc)1588 int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
1589 {
1590     size_t pos = 0;
1591     size_t last;
1592     std::string token = getNextToken(line, pos, &last, WHITESPACE);
1593     pos = last;
1594 
1595     if (token == "base_opcode") {
1596         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1597         if (str.size() == 0) {
1598             fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc);
1599         } else {
1600             setBaseOpcode(atoi(str.c_str()));
1601         }
1602     } else  if (token == "encoder_headers") {
1603         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1604         pos = last;
1605         while (str.size() != 0) {
1606             encoderHeaders().push_back(str);
1607             str = getNextToken(line, pos, &last, WHITESPACE);
1608             pos = last;
1609         }
1610     } else if (token == "client_context_headers") {
1611         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1612         pos = last;
1613         while (str.size() != 0) {
1614             clientContextHeaders().push_back(str);
1615             str = getNextToken(line, pos, &last, WHITESPACE);
1616             pos = last;
1617         }
1618     } else if (token == "server_context_headers") {
1619         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1620         pos = last;
1621         while (str.size() != 0) {
1622             serverContextHeaders().push_back(str);
1623             str = getNextToken(line, pos, &last, WHITESPACE);
1624             pos = last;
1625         }
1626     } else if (token == "decoder_headers") {
1627         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1628         pos = last;
1629         while (str.size() != 0) {
1630             decoderHeaders().push_back(str);
1631             str = getNextToken(line, pos, &last, WHITESPACE);
1632             pos = last;
1633         }
1634     }
1635     else {
1636         fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
1637     }
1638 
1639     return 0;
1640 }
1641