1#include "spec.h"
2#include <stdio.h>
3#include <string.h>
4
5#define LOCAL_FIFO_PREFIX "LF_"
6#define RS_PLAYBACK_PREFIX "rsp_"
7#define RS_INTERNAL_PREFIX "rsi_"
8
9#define RSG_API_CPP_DOC                                                     \
10"/*\n"                                                                      \
11" * rsgApi.cpp\n"                                                           \
12" * This file implements the functions responsible for sending messages\n"  \
13" * to the RS driver layer. The messages are sent through a FIFO that is\n" \
14" * shared between the process's caller threads and driver thread.\n"       \
15" */\n\n"
16
17#define RSG_API_REPLAY_CPP_DOC                                              \
18"/*\n"                                                                      \
19" * rsgApiReplay.cpp\n"                                                     \
20" * This file implements the functions responsible for reading messages\n"  \
21" * sent to the RS driver layer.\n"                                         \
22" */\n\n"
23
24void printFileHeader(FILE *f) {
25    fprintf(f, "/*\n");
26    fprintf(f, " * Copyright (C) 2015 The Android Open Source Project\n");
27    fprintf(f, " *\n");
28    fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n");
29    fprintf(f, " * you may not use this file except in compliance with the License.\n");
30    fprintf(f, " * You may obtain a copy of the License at\n");
31    fprintf(f, " *\n");
32    fprintf(f, " *      http://www.apache.org/licenses/LICENSE-2.0\n");
33    fprintf(f, " *\n");
34    fprintf(f, " * Unless required by applicable law or agreed to in writing, software\n");
35    fprintf(f, " * distributed under the License is distributed on an \"AS IS\" BASIS,\n");
36    fprintf(f, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
37    fprintf(f, " * See the License for the specific language governing permissions and\n");
38    fprintf(f, " * limitations under the License.\n");
39    fprintf(f, " */\n\n");
40}
41
42void printVarType(FILE *f, const VarType *vt) {
43    int ct;
44    if (vt->isConst) {
45        fprintf(f, "const ");
46    }
47
48    switch (vt->type) {
49    case 0:
50        fprintf(f, "void");
51        break;
52    case 1:
53        fprintf(f, "int%i_t", vt->bits);
54        break;
55    case 2:
56        fprintf(f, "uint%i_t", vt->bits);
57        break;
58    case 3:
59        if (vt->bits == 32)
60            fprintf(f, "float");
61        else
62            fprintf(f, "double");
63        break;
64    case 4:
65        fprintf(f, "%s", vt->typeName);
66        break;
67    }
68
69    if (vt->ptrLevel) {
70        fprintf(f, " ");
71        for (ct=0; ct < vt->ptrLevel; ct++) {
72            fprintf(f, "*");
73        }
74    }
75}
76
77void printVarTypeAndName(FILE *f, const VarType *vt) {
78    printVarType(f, vt);
79
80    if (vt->name[0]) {
81        fprintf(f, " %s", vt->name);
82    }
83}
84
85void printArgList(FILE *f, const ApiEntry * api, int assumePrevious) {
86    int ct;
87    for (ct=0; ct < api->paramCount; ct++) {
88        if (ct || assumePrevious) {
89            fprintf(f, ", ");
90        }
91        printVarTypeAndName(f, &api->params[ct]);
92    }
93}
94
95void printStructures(FILE *f) {
96    int ct;
97    int ct2;
98
99    for (ct=0; ct < apiCount; ct++) {
100        fprintf(f, "typedef struct RS_CMD_%s_rec RS_CMD_%s;\n", apis[ct].name, apis[ct].name);
101    }
102    fprintf(f, "\n");
103
104    for (ct=0; ct < apiCount; ct++) {
105        const ApiEntry * api = &apis[ct];
106        fprintf(f, "#define RS_CMD_ID_%s %i\n", api->name, ct+1);
107        fprintf(f, "struct __attribute__((packed)) RS_CMD_%s_rec {\n", api->name);
108        //fprintf(f, "    RsCommandHeader _hdr;\n");
109
110        for (ct2=0; ct2 < api->paramCount; ct2++) {
111            fprintf(f, "    ");
112            printVarTypeAndName(f, &api->params[ct2]);
113            fprintf(f, ";\n");
114        }
115        fprintf(f, "};\n\n");
116    }
117}
118
119void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext, int isFnPtr) {
120    printVarTypeAndName(f, &api->ret);
121    if (isFnPtr) {
122        char t[1024];
123        strncpy(t, api->name, sizeof(t)-1);
124        t[sizeof(t)-1] = '\0';
125        if (strlen(prefix) == 0) {
126            if (t[0] > 'A' && t[0] < 'Z') {
127                t[0] -= 'A' - 'a';
128            }
129        }
130        fprintf(f, " (* %s%s) (", prefix, api->name);
131    } else {
132        fprintf(f, " %s%s (", prefix, api->name);
133    }
134    if (!api->nocontext) {
135        if (addContext) {
136            fprintf(f, "Context *");
137        } else {
138            fprintf(f, "RsContext rsc");
139        }
140    }
141    printArgList(f, api, !api->nocontext);
142    fprintf(f, ")");
143}
144
145void printFuncDecls(FILE *f, const char *prefix, int addContext, int externC) {
146    int ct;
147    for (ct=0; ct < apiCount; ct++) {
148        if (externC) {
149            fprintf(f, "extern \"C\" ");
150        }
151        printFuncDecl(f, &apis[ct], prefix, addContext, 0);
152        fprintf(f, ";\n");
153    }
154    fprintf(f, "\n\n");
155}
156
157void printPlaybackFuncs(FILE *f, const char *prefix) {
158    int ct;
159    for (ct=0; ct < apiCount; ct++) {
160        if (apis[ct].direct) {
161            continue;
162        }
163
164        fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name);
165    }
166}
167
168static int hasInlineDataPointers(const ApiEntry * api) {
169    int ret = 0;
170    int ct;
171    if (api->sync || api->ret.typeName[0]) {
172        return 0;
173    }
174    for (ct=0; ct < api->paramCount; ct++) {
175        const VarType *vt = &api->params[ct];
176
177        if (!vt->isConst && vt->ptrLevel) {
178            // Non-const pointers cannot be inlined.
179            return 0;
180        }
181        if (vt->ptrLevel > 1) {
182            // not handled yet.
183            return 0;
184        }
185
186        if (vt->isConst && vt->ptrLevel) {
187            // Non-const pointers cannot be inlined.
188            ret = 1;
189        }
190    }
191    return ret;
192}
193
194void printApiCpp(FILE *f) {
195    int ct;
196    int ct2;
197
198    fprintf(f, RSG_API_CPP_DOC);
199
200    fprintf(f, "#include \"rsDevice.h\"\n");
201    fprintf(f, "#include \"rsContext.h\"\n");
202    fprintf(f, "#include \"rsThreadIO.h\"\n");
203    fprintf(f, "#include \"rsgApiStructs.h\"\n");
204    fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
205    fprintf(f, "#include \"rsFifo.h\"\n");
206    fprintf(f, "\n");
207    fprintf(f, "using namespace android;  // NOLINT\n");
208    fprintf(f, "using namespace android::renderscript;  // NOLINT\n");
209    fprintf(f, "\n");
210
211    // Generate RS funcs that send messages on the local FIFO.
212    for (ct=0; ct < apiCount; ct++) {
213        int needFlush = 0;
214        const ApiEntry * api = &apis[ct];
215
216        fprintf(f, "static ");
217        printFuncDecl(f, api, LOCAL_FIFO_PREFIX, 0, 0);
218        fprintf(f, "\n{\n");
219        if (api->direct) {
220            fprintf(f, "    ");
221            if (api->ret.typeName[0]) {
222                fprintf(f, "return ");
223            }
224            fprintf(f, RS_INTERNAL_PREFIX "%s(", api->name);
225            if (!api->nocontext) {
226                fprintf(f, "(Context *)rsc");
227            }
228            for (ct2=0; ct2 < api->paramCount; ct2++) {
229                const VarType *vt = &api->params[ct2];
230                if (ct2 > 0 || !api->nocontext) {
231                    fprintf(f, ", ");
232                }
233                fprintf(f, "%s", vt->name);
234            }
235            fprintf(f, ");\n");
236        } else if (api->handcodeApi) {
237            // handle handcode path
238            fprintf(f, "    " LOCAL_FIFO_PREFIX "%s_handcode(", api->name);
239            if (!api->nocontext) {
240                fprintf(f, "(Context *)rsc");
241            }
242            for (ct2=0; ct2 < api->paramCount; ct2++) {
243                const VarType *vt = &api->params[ct2];
244                if (ct2 > 0 || !api->nocontext) {
245                    fprintf(f, ", ");
246                }
247                fprintf(f, "%s", vt->name);
248            }
249            fprintf(f, ");\n");
250
251        } else {
252            // handle synchronous path
253            fprintf(f, "    if (((Context *)rsc)->isSynchronous()) {\n");
254            fprintf(f, "        ");
255            if (api->ret.typeName[0]) {
256                fprintf(f, "return ");
257            }
258            fprintf(f, RS_INTERNAL_PREFIX "%s(", api->name);
259            if (!api->nocontext) {
260                fprintf(f, "(Context *)rsc");
261            }
262            for (ct2=0; ct2 < api->paramCount; ct2++) {
263                const VarType *vt = &api->params[ct2];
264                if (ct2 > 0 || !api->nocontext) {
265                    fprintf(f, ", ");
266                }
267                fprintf(f, "%s", vt->name);
268            }
269            fprintf(f, ");\n");
270            if (!api->ret.typeName[0]) {
271                fprintf(f, "    return;");
272            }
273            fprintf(f, "    }\n\n");
274
275            fprintf(f, "    ThreadIO *io = &((Context *)rsc)->mIO;\n");
276            fprintf(f, "    const size_t size = sizeof(RS_CMD_%s);\n", api->name);
277            if (hasInlineDataPointers(api)) {
278                fprintf(f, "    size_t dataSize = 0;\n");
279                for (ct2=0; ct2 < api->paramCount; ct2++) {
280                    const VarType *vt = &api->params[ct2];
281                    if (vt->isConst && vt->ptrLevel) {
282                        fprintf(f, "    dataSize += %s_length;\n", vt->name);
283                    }
284                }
285            }
286
287            //fprintf(f, "    ALOGE(\"add command %s\\n\");\n", api->name);
288            if (hasInlineDataPointers(api)) {
289                fprintf(f, "    RS_CMD_%s *cmd = NULL;\n", api->name);
290                fprintf(f, "    if (dataSize < io->getMaxInlineSize()) {;\n");
291                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name);
292                fprintf(f, "    } else {\n");
293                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name);
294                fprintf(f, "    }\n");
295                fprintf(f, "    uint8_t *payload = (uint8_t *)&cmd[1];\n");
296            } else {
297                fprintf(f, "    RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name, api->name);
298            }
299
300            for (ct2=0; ct2 < api->paramCount; ct2++) {
301                const VarType *vt = &api->params[ct2];
302                needFlush += vt->ptrLevel;
303                if (vt->ptrLevel && hasInlineDataPointers(api)) {
304                    fprintf(f, "    if (%s_length == 0) {\n", vt->name);
305                    fprintf(f, "        cmd->%s = NULL;\n", vt->name);
306                    fprintf(f, "    } else if (dataSize < io->getMaxInlineSize()) {\n");
307                    fprintf(f, "        memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
308                    fprintf(f, "        cmd->%s = (", vt->name);
309                    printVarType(f, vt);
310                    fprintf(f, ")(payload - ((uint8_t *)&cmd[1]));\n");
311                    fprintf(f, "        payload += %s_length;\n", vt->name);
312                    fprintf(f, "    } else {\n");
313                    fprintf(f, "        cmd->%s = %s;\n", vt->name, vt->name);
314                    fprintf(f, "    }\n");
315
316                } else {
317                    fprintf(f, "    cmd->%s = %s;\n", vt->name, vt->name);
318                }
319            }
320            if (api->ret.typeName[0] || api->sync) {
321                needFlush = 1;
322            }
323
324            fprintf(f, "    io->coreCommit();\n");
325            if (hasInlineDataPointers(api)) {
326                fprintf(f, "    if (dataSize >= io->getMaxInlineSize()) {\n");
327                fprintf(f, "        io->coreGetReturn(NULL, 0);\n");
328                fprintf(f, "    }\n");
329            } else if (api->ret.typeName[0]) {
330                fprintf(f, "\n    ");
331                printVarType(f, &api->ret);
332                fprintf(f, " ret;\n");
333                fprintf(f, "    io->coreGetReturn(&ret, sizeof(ret));\n");
334                fprintf(f, "    return ret;\n");
335            } else if (needFlush) {
336                fprintf(f, "    io->coreGetReturn(NULL, 0);\n");
337            }
338        }
339        fprintf(f, "};\n\n");
340    }
341
342    fprintf(f, "\n");
343
344    for (ct=0; ct < apiCount; ct++) {
345        int needFlush = 0;
346        const ApiEntry * api = &apis[ct];
347
348        fprintf(f, "extern \"C\" ");
349
350        printFuncDecl(f, api, "rs", 0, 0);
351        fprintf(f, "\n{\n");
352        fprintf(f, "    ");
353        if (api->ret.typeName[0]) {
354            fprintf(f, "return ");
355        }
356        fprintf(f, LOCAL_FIFO_PREFIX "%s(", api->name);
357
358        if (!api->nocontext) {
359            fprintf(f, "(Context *)rsc");
360        }
361
362        for (ct2=0; ct2 < api->paramCount; ct2++) {
363            const VarType *vt = &api->params[ct2];
364            if (ct2 > 0 || !api->nocontext) {
365                fprintf(f, ", ");
366            }
367            fprintf(f, "%s", vt->name);
368        }
369        fprintf(f, ");\n");
370        fprintf(f, "}\n\n");
371    }
372
373}
374
375void printPlaybackCpp(FILE *f) {
376    int ct;
377    int ct2;
378
379    fprintf(f, RSG_API_REPLAY_CPP_DOC);
380
381    fprintf(f, "#include \"rsDevice.h\"\n");
382    fprintf(f, "#include \"rsContext.h\"\n");
383    fprintf(f, "#include \"rsThreadIO.h\"\n");
384    fprintf(f, "#include \"rsgApiStructs.h\"\n");
385    fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
386    fprintf(f, "\n");
387    fprintf(f, "namespace android {\n");
388    fprintf(f, "namespace renderscript {\n");
389    fprintf(f, "\n");
390
391    // Generate functions to play back messages sent from the local FIFO.
392    for (ct=0; ct < apiCount; ct++) {
393        const ApiEntry * api = &apis[ct];
394        int needFlush = 0;
395
396        if (api->direct) {
397            continue;
398        }
399
400        fprintf(f, "void " RS_PLAYBACK_PREFIX "%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name);
401        fprintf(f, "    const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
402
403        if (hasInlineDataPointers(api)) {
404            fprintf(f, "    const uint8_t *baseData = 0;\n");
405            fprintf(f, "    if (cmdSizeBytes != sizeof(RS_CMD_%s)) {\n", api->name);
406            fprintf(f, "        baseData = &((const uint8_t *)vp)[sizeof(*cmd)];\n");
407            fprintf(f, "    }\n");
408        }
409
410        fprintf(f, "    ");
411        if (api->ret.typeName[0]) {
412            fprintf(f, "\n    ");
413            printVarType(f, &api->ret);
414            fprintf(f, " ret = ");
415        }
416        fprintf(f, RS_INTERNAL_PREFIX "%s(con", api->name);
417        for (ct2=0; ct2 < api->paramCount; ct2++) {
418            const VarType *vt = &api->params[ct2];
419            needFlush += vt->ptrLevel;
420
421            if (hasInlineDataPointers(api) && vt->ptrLevel) {
422                fprintf(f, ",\n           cmd->%s_length == 0 ? NULL : (const %s *)&baseData[(intptr_t)cmd->%s]",
423                        vt->name, vt->typeName, vt->name);
424            } else {
425                fprintf(f, ",\n           cmd->%s", vt->name);
426            }
427        }
428        fprintf(f, ");\n");
429
430        if (hasInlineDataPointers(api)) {
431            fprintf(f, "    size_t totalSize = 0;\n");
432            for (ct2=0; ct2 < api->paramCount; ct2++) {
433                if (api->params[ct2].ptrLevel) {
434                    fprintf(f, "    totalSize += cmd->%s_length;\n", api->params[ct2].name);
435                }
436            }
437
438            fprintf(f, "    if ((totalSize != 0) && (cmdSizeBytes == sizeof(RS_CMD_%s))) {\n", api->name);
439            fprintf(f, "        con->mIO.coreSetReturn(NULL, 0);\n");
440            fprintf(f, "    }\n");
441        } else if (api->ret.typeName[0]) {
442            fprintf(f, "    con->mIO.coreSetReturn(&ret, sizeof(ret));\n");
443        } else if (api->sync || needFlush) {
444            fprintf(f, "    con->mIO.coreSetReturn(NULL, 0);\n");
445        }
446
447        fprintf(f, "};\n\n");
448    }
449
450    // Generate the globally accessible table of playback functions.
451    fprintf(f, "RsPlaybackLocalFunc gPlaybackFuncs[%i] = {\n", apiCount + 1);
452    fprintf(f, "    NULL,\n");
453    for (ct=0; ct < apiCount; ct++) {
454        if (apis[ct].direct) {
455            fprintf(f, "    NULL,\n");
456        } else {
457            fprintf(f, "    %s%s,\n", RS_PLAYBACK_PREFIX, apis[ct].name);
458        }
459    }
460    fprintf(f, "};\n");
461
462    fprintf(f, "};\n");
463    fprintf(f, "};\n");
464}
465
466void yylex();
467
468int main(int argc, char **argv) {
469    if (argc != 3) {
470        fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]);
471        return 1;
472    }
473    const char* rsgFile = argv[1];
474    const char* outFile = argv[2];
475    FILE* input = fopen(rsgFile, "r");
476
477    char choice = fgetc(input);
478    fclose(input);
479
480    if (choice < '0' || choice > '3') {
481        fprintf(stderr, "Uknown command: \'%c\'\n", choice);
482        return -2;
483    }
484
485    yylex();
486    // printf("# of lines = %d\n", num_lines);
487
488    FILE *f = fopen(outFile, "w");
489
490    printFileHeader(f);
491    switch (choice) {
492        case '0': // rsgApiStructs.h
493        {
494            fprintf(f, "\n");
495            fprintf(f, "#include \"rsContext.h\"\n");
496            fprintf(f, "#include \"rsFifo.h\"\n");
497            fprintf(f, "\n");
498            fprintf(f, "namespace android {\n");
499            fprintf(f, "namespace renderscript {\n");
500            printStructures(f);
501            printFuncDecls(f, RS_INTERNAL_PREFIX, 1, 0);
502            printPlaybackFuncs(f, RS_PLAYBACK_PREFIX);
503            fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n");
504            fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1);
505
506            fprintf(f, "}\n");
507            fprintf(f, "}\n");
508        }
509        break;
510
511        case '1': // rsgApiFuncDecl.h
512        {
513            printFuncDecls(f, "rs", 0, 1);
514        }
515        break;
516
517        case '2': // rsgApi.cpp
518        {
519            printApiCpp(f);
520        }
521        break;
522
523        case '3': // rsgApiReplay.cpp
524        {
525            printPlaybackCpp(f);
526        }
527        break;
528    }
529    fclose(f);
530    return 0;
531}
532