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        strcpy(t, api->name);
124        if (strlen(prefix) == 0) {
125            if (t[0] > 'A' && t[0] < 'Z') {
126                t[0] -= 'A' - 'a';
127            }
128        }
129        fprintf(f, " (* %s%s) (", prefix, api->name);
130    } else {
131        fprintf(f, " %s%s (", prefix, api->name);
132    }
133    if (!api->nocontext) {
134        if (addContext) {
135            fprintf(f, "Context *");
136        } else {
137            fprintf(f, "RsContext rsc");
138        }
139    }
140    printArgList(f, api, !api->nocontext);
141    fprintf(f, ")");
142}
143
144void printFuncDecls(FILE *f, const char *prefix, int addContext, int externC) {
145    int ct;
146    for (ct=0; ct < apiCount; ct++) {
147        if (externC) {
148            fprintf(f, "extern \"C\" ");
149        }
150        printFuncDecl(f, &apis[ct], prefix, addContext, 0);
151        fprintf(f, ";\n");
152    }
153    fprintf(f, "\n\n");
154}
155
156void printPlaybackFuncs(FILE *f, const char *prefix) {
157    int ct;
158    for (ct=0; ct < apiCount; ct++) {
159        if (apis[ct].direct) {
160            continue;
161        }
162
163        fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name);
164    }
165}
166
167static int hasInlineDataPointers(const ApiEntry * api) {
168    int ret = 0;
169    int ct;
170    if (api->sync || api->ret.typeName[0]) {
171        return 0;
172    }
173    for (ct=0; ct < api->paramCount; ct++) {
174        const VarType *vt = &api->params[ct];
175
176        if (!vt->isConst && vt->ptrLevel) {
177            // Non-const pointers cannot be inlined.
178            return 0;
179        }
180        if (vt->ptrLevel > 1) {
181            // not handled yet.
182            return 0;
183        }
184
185        if (vt->isConst && vt->ptrLevel) {
186            // Non-const pointers cannot be inlined.
187            ret = 1;
188        }
189    }
190    return ret;
191}
192
193void printApiCpp(FILE *f) {
194    int ct;
195    int ct2;
196
197    fprintf(f, RSG_API_CPP_DOC);
198
199    fprintf(f, "#include \"rsDevice.h\"\n");
200    fprintf(f, "#include \"rsContext.h\"\n");
201    fprintf(f, "#include \"rsThreadIO.h\"\n");
202    fprintf(f, "#include \"rsgApiStructs.h\"\n");
203    fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
204    fprintf(f, "#include \"rsFifo.h\"\n");
205    fprintf(f, "\n");
206    fprintf(f, "using namespace android;\n");
207    fprintf(f, "using namespace android::renderscript;\n");
208    fprintf(f, "\n");
209
210    // Generate RS funcs that send messages on the local FIFO.
211    for (ct=0; ct < apiCount; ct++) {
212        int needFlush = 0;
213        const ApiEntry * api = &apis[ct];
214
215        fprintf(f, "static ");
216        printFuncDecl(f, api, LOCAL_FIFO_PREFIX, 0, 0);
217        fprintf(f, "\n{\n");
218        if (api->direct) {
219            fprintf(f, "    ");
220            if (api->ret.typeName[0]) {
221                fprintf(f, "return ");
222            }
223            fprintf(f, RS_INTERNAL_PREFIX "%s(", api->name);
224            if (!api->nocontext) {
225                fprintf(f, "(Context *)rsc");
226            }
227            for (ct2=0; ct2 < api->paramCount; ct2++) {
228                const VarType *vt = &api->params[ct2];
229                if (ct2 > 0 || !api->nocontext) {
230                    fprintf(f, ", ");
231                }
232                fprintf(f, "%s", vt->name);
233            }
234            fprintf(f, ");\n");
235        } else if (api->handcodeApi) {
236            // handle handcode path
237            fprintf(f, "    " LOCAL_FIFO_PREFIX "%s_handcode(", api->name);
238            if (!api->nocontext) {
239                fprintf(f, "(Context *)rsc");
240            }
241            for (ct2=0; ct2 < api->paramCount; ct2++) {
242                const VarType *vt = &api->params[ct2];
243                if (ct2 > 0 || !api->nocontext) {
244                    fprintf(f, ", ");
245                }
246                fprintf(f, "%s", vt->name);
247            }
248            fprintf(f, ");\n");
249
250        } else {
251            // handle synchronous path
252            fprintf(f, "    if (((Context *)rsc)->isSynchronous()) {\n");
253            fprintf(f, "        ");
254            if (api->ret.typeName[0]) {
255                fprintf(f, "return ");
256            }
257            fprintf(f, RS_INTERNAL_PREFIX "%s(", api->name);
258            if (!api->nocontext) {
259                fprintf(f, "(Context *)rsc");
260            }
261            for (ct2=0; ct2 < api->paramCount; ct2++) {
262                const VarType *vt = &api->params[ct2];
263                if (ct2 > 0 || !api->nocontext) {
264                    fprintf(f, ", ");
265                }
266                fprintf(f, "%s", vt->name);
267            }
268            fprintf(f, ");\n");
269            if (!api->ret.typeName[0]) {
270                fprintf(f, "    return;");
271            }
272            fprintf(f, "    }\n\n");
273
274            fprintf(f, "    ThreadIO *io = &((Context *)rsc)->mIO;\n");
275            fprintf(f, "    const size_t size = sizeof(RS_CMD_%s);\n", api->name);
276            if (hasInlineDataPointers(api)) {
277                fprintf(f, "    size_t dataSize = 0;\n");
278                for (ct2=0; ct2 < api->paramCount; ct2++) {
279                    const VarType *vt = &api->params[ct2];
280                    if (vt->isConst && vt->ptrLevel) {
281                        fprintf(f, "    dataSize += %s_length;\n", vt->name);
282                    }
283                }
284            }
285
286            //fprintf(f, "    ALOGE(\"add command %s\\n\");\n", api->name);
287            if (hasInlineDataPointers(api)) {
288                fprintf(f, "    RS_CMD_%s *cmd = NULL;\n", api->name);
289                fprintf(f, "    if (dataSize < io->getMaxInlineSize()) {;\n");
290                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name);
291                fprintf(f, "    } else {\n");
292                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name);
293                fprintf(f, "    }\n");
294                fprintf(f, "    uint8_t *payload = (uint8_t *)&cmd[1];\n");
295            } else {
296                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);
297            }
298
299            for (ct2=0; ct2 < api->paramCount; ct2++) {
300                const VarType *vt = &api->params[ct2];
301                needFlush += vt->ptrLevel;
302                if (vt->ptrLevel && hasInlineDataPointers(api)) {
303                    fprintf(f, "    if (%s_length == 0) {\n", vt->name);
304                    fprintf(f, "        cmd->%s = NULL;\n", vt->name);
305                    fprintf(f, "    } else if (dataSize < io->getMaxInlineSize()) {\n");
306                    fprintf(f, "        memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
307                    fprintf(f, "        cmd->%s = (", vt->name);
308                    printVarType(f, vt);
309                    fprintf(f, ")(payload - ((uint8_t *)&cmd[1]));\n");
310                    fprintf(f, "        payload += %s_length;\n", vt->name);
311                    fprintf(f, "    } else {\n");
312                    fprintf(f, "        cmd->%s = %s;\n", vt->name, vt->name);
313                    fprintf(f, "    }\n");
314
315                } else {
316                    fprintf(f, "    cmd->%s = %s;\n", vt->name, vt->name);
317                }
318            }
319            if (api->ret.typeName[0] || api->sync) {
320                needFlush = 1;
321            }
322
323            fprintf(f, "    io->coreCommit();\n");
324            if (hasInlineDataPointers(api)) {
325                fprintf(f, "    if (dataSize >= io->getMaxInlineSize()) {\n");
326                fprintf(f, "        io->coreGetReturn(NULL, 0);\n");
327                fprintf(f, "    }\n");
328            } else if (api->ret.typeName[0]) {
329                fprintf(f, "\n    ");
330                printVarType(f, &api->ret);
331                fprintf(f, " ret;\n");
332                fprintf(f, "    io->coreGetReturn(&ret, sizeof(ret));\n");
333                fprintf(f, "    return ret;\n");
334            } else if (needFlush) {
335                fprintf(f, "    io->coreGetReturn(NULL, 0);\n");
336            }
337        }
338        fprintf(f, "};\n\n");
339    }
340
341    fprintf(f, "\n");
342
343    for (ct=0; ct < apiCount; ct++) {
344        int needFlush = 0;
345        const ApiEntry * api = &apis[ct];
346
347        fprintf(f, "extern \"C\" ");
348
349        printFuncDecl(f, api, "rs", 0, 0);
350        fprintf(f, "\n{\n");
351        fprintf(f, "    ");
352        if (api->ret.typeName[0]) {
353            fprintf(f, "return ");
354        }
355        fprintf(f, LOCAL_FIFO_PREFIX "%s(", api->name);
356
357        if (!api->nocontext) {
358            fprintf(f, "(Context *)rsc");
359        }
360
361        for (ct2=0; ct2 < api->paramCount; ct2++) {
362            const VarType *vt = &api->params[ct2];
363            if (ct2 > 0 || !api->nocontext) {
364                fprintf(f, ", ");
365            }
366            fprintf(f, "%s", vt->name);
367        }
368        fprintf(f, ");\n");
369        fprintf(f, "}\n\n");
370    }
371
372}
373
374void printPlaybackCpp(FILE *f) {
375    int ct;
376    int ct2;
377
378    fprintf(f, RSG_API_REPLAY_CPP_DOC);
379
380    fprintf(f, "#include \"rsDevice.h\"\n");
381    fprintf(f, "#include \"rsContext.h\"\n");
382    fprintf(f, "#include \"rsThreadIO.h\"\n");
383    fprintf(f, "#include \"rsgApiStructs.h\"\n");
384    fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
385    fprintf(f, "\n");
386    fprintf(f, "namespace android {\n");
387    fprintf(f, "namespace renderscript {\n");
388    fprintf(f, "\n");
389
390    // Generate functions to play back messages sent from the local FIFO.
391    for (ct=0; ct < apiCount; ct++) {
392        const ApiEntry * api = &apis[ct];
393        int needFlush = 0;
394
395        if (api->direct) {
396            continue;
397        }
398
399        fprintf(f, "void " RS_PLAYBACK_PREFIX "%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name);
400        fprintf(f, "    const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
401
402        if (hasInlineDataPointers(api)) {
403            fprintf(f, "    const uint8_t *baseData = 0;\n");
404            fprintf(f, "    if (cmdSizeBytes != sizeof(RS_CMD_%s)) {\n", api->name);
405            fprintf(f, "        baseData = &((const uint8_t *)vp)[sizeof(*cmd)];\n");
406            fprintf(f, "    }\n");
407        }
408
409        fprintf(f, "    ");
410        if (api->ret.typeName[0]) {
411            fprintf(f, "\n    ");
412            printVarType(f, &api->ret);
413            fprintf(f, " ret = ");
414        }
415        fprintf(f, RS_INTERNAL_PREFIX "%s(con", api->name);
416        for (ct2=0; ct2 < api->paramCount; ct2++) {
417            const VarType *vt = &api->params[ct2];
418            needFlush += vt->ptrLevel;
419
420            if (hasInlineDataPointers(api) && vt->ptrLevel) {
421                fprintf(f, ",\n           cmd->%s_length == 0 ? NULL : (const %s *)&baseData[(intptr_t)cmd->%s]",
422                        vt->name, vt->typeName, vt->name);
423            } else {
424                fprintf(f, ",\n           cmd->%s", vt->name);
425            }
426        }
427        fprintf(f, ");\n");
428
429        if (hasInlineDataPointers(api)) {
430            fprintf(f, "    size_t totalSize = 0;\n");
431            for (ct2=0; ct2 < api->paramCount; ct2++) {
432                if (api->params[ct2].ptrLevel) {
433                    fprintf(f, "    totalSize += cmd->%s_length;\n", api->params[ct2].name);
434                }
435            }
436
437            fprintf(f, "    if ((totalSize != 0) && (cmdSizeBytes == sizeof(RS_CMD_%s))) {\n", api->name);
438            fprintf(f, "        con->mIO.coreSetReturn(NULL, 0);\n");
439            fprintf(f, "    }\n");
440        } else if (api->ret.typeName[0]) {
441            fprintf(f, "    con->mIO.coreSetReturn(&ret, sizeof(ret));\n");
442        } else if (api->sync || needFlush) {
443            fprintf(f, "    con->mIO.coreSetReturn(NULL, 0);\n");
444        }
445
446        fprintf(f, "};\n\n");
447    }
448
449    // Generate the globally accessible table of playback functions.
450    fprintf(f, "RsPlaybackLocalFunc gPlaybackFuncs[%i] = {\n", apiCount + 1);
451    fprintf(f, "    NULL,\n");
452    for (ct=0; ct < apiCount; ct++) {
453        if (apis[ct].direct) {
454            fprintf(f, "    NULL,\n");
455        } else {
456            fprintf(f, "    %s%s,\n", RS_PLAYBACK_PREFIX, apis[ct].name);
457        }
458    }
459    fprintf(f, "};\n");
460
461    fprintf(f, "};\n");
462    fprintf(f, "};\n");
463}
464
465void yylex();
466
467int main(int argc, char **argv) {
468    if (argc != 3) {
469        fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]);
470        return 1;
471    }
472    const char* rsgFile = argv[1];
473    const char* outFile = argv[2];
474    FILE* input = fopen(rsgFile, "r");
475
476    char choice = fgetc(input);
477    fclose(input);
478
479    if (choice < '0' || choice > '3') {
480        fprintf(stderr, "Uknown command: \'%c\'\n", choice);
481        return -2;
482    }
483
484    yylex();
485    // printf("# of lines = %d\n", num_lines);
486
487    FILE *f = fopen(outFile, "w");
488
489    printFileHeader(f);
490    switch (choice) {
491        case '0': // rsgApiStructs.h
492        {
493            fprintf(f, "\n");
494            fprintf(f, "#include \"rsContext.h\"\n");
495            fprintf(f, "#include \"rsFifo.h\"\n");
496            fprintf(f, "\n");
497            fprintf(f, "namespace android {\n");
498            fprintf(f, "namespace renderscript {\n");
499            printStructures(f);
500            printFuncDecls(f, RS_INTERNAL_PREFIX, 1, 0);
501            printPlaybackFuncs(f, RS_PLAYBACK_PREFIX);
502            fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n");
503            fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1);
504
505            fprintf(f, "}\n");
506            fprintf(f, "}\n");
507        }
508        break;
509
510        case '1': // rsgApiFuncDecl.h
511        {
512            printFuncDecls(f, "rs", 0, 1);
513        }
514        break;
515
516        case '2': // rsgApi.cpp
517        {
518            printApiCpp(f);
519        }
520        break;
521
522        case '3': // rsgApiReplay.cpp
523        {
524            printPlaybackCpp(f);
525        }
526        break;
527    }
528    fclose(f);
529    return 0;
530}
531