Home | History | Annotate | Download | only in glsl_tests
      1 /*
      2  * Copyright  2014 Intel Corporation
      3  * Copyright  2016 Advanced Micro Devices, Inc.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * This program reads and compiles multiple GLSL shaders from one source file.
     27  * Each shader must begin with the #shader directive. Syntax:
     28  *     #shader [vs|tcs|tes|gs|ps|cs] [name]
     29  *
     30  * The shader name is printed, followed by the stderr output from
     31  * glCreateShaderProgramv. (radeonsi prints the shader disassembly there)
     32  *
     33  * The optional parameter -mcpu=[processor] forces radeonsi to compile for
     34  * the specified GPU processor. (e.g. tahiti, bonaire, tonga)
     35  *
     36  * The program doesn't check if the underlying driver is really radeonsi.
     37  * OpenGL 4.3 Core profile is required.
     38  */
     39 
     40 /* for asprintf() */
     41 #define _GNU_SOURCE
     42 
     43 #include <stdio.h>
     44 #include <fcntl.h>
     45 #include <string.h>
     46 #include <stdlib.h>
     47 
     48 #include <epoxy/gl.h>
     49 #include <epoxy/egl.h>
     50 #include <gbm.h>
     51 
     52 #define unlikely(x) __builtin_expect(!!(x), 0)
     53 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
     54 
     55 static int fd;
     56 static EGLDisplay egl_dpy;
     57 static EGLContext ctx;
     58 
     59 static void
     60 create_gl_core_context()
     61 {
     62     const char *client_extensions = eglQueryString(EGL_NO_DISPLAY,
     63                                                    EGL_EXTENSIONS);
     64     if (!client_extensions) {
     65         fprintf(stderr, "ERROR: Missing EGL_EXT_client_extensions\n");
     66         exit(1);
     67     }
     68 
     69     if (!strstr(client_extensions, "EGL_MESA_platform_gbm")) {
     70         fprintf(stderr, "ERROR: Missing EGL_MESA_platform_gbm\n");
     71         exit(1);
     72     }
     73 
     74     fd = open("/dev/dri/renderD128", O_RDWR);
     75     if (unlikely(fd < 0)) {
     76         fprintf(stderr, "ERROR: Couldn't open /dev/dri/renderD128\n");
     77         exit(1);
     78     }
     79 
     80     struct gbm_device *gbm = gbm_create_device(fd);
     81     if (unlikely(gbm == NULL)) {
     82         fprintf(stderr, "ERROR: Couldn't create gbm device\n");
     83         exit(1);
     84     }
     85 
     86     egl_dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA,
     87                                        gbm, NULL);
     88     if (unlikely(egl_dpy == EGL_NO_DISPLAY)) {
     89         fprintf(stderr, "ERROR: eglGetDisplay() failed\n");
     90         exit(1);
     91     }
     92 
     93     if (unlikely(!eglInitialize(egl_dpy, NULL, NULL))) {
     94         fprintf(stderr, "ERROR: eglInitialize() failed\n");
     95         exit(1);
     96     }
     97 
     98     static const char *egl_extension[] = {
     99             "EGL_KHR_create_context",
    100             "EGL_KHR_surfaceless_context"
    101     };
    102     const char *extension_string = eglQueryString(egl_dpy, EGL_EXTENSIONS);
    103     for (int i = 0; i < ARRAY_SIZE(egl_extension); i++) {
    104         if (strstr(extension_string, egl_extension[i]) == NULL) {
    105             fprintf(stderr, "ERROR: Missing %s\n", egl_extension[i]);
    106             exit(1);
    107         }
    108     }
    109 
    110     static const EGLint config_attribs[] = {
    111         EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    112         EGL_NONE
    113     };
    114     EGLConfig cfg;
    115     EGLint count;
    116 
    117     if (!eglChooseConfig(egl_dpy, config_attribs, &cfg, 1, &count) ||
    118         count == 0) {
    119         fprintf(stderr, "ERROR: eglChooseConfig() failed\n");
    120         exit(1);
    121     }
    122     eglBindAPI(EGL_OPENGL_API);
    123 
    124     static const EGLint attribs[] = {
    125         EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
    126         EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
    127         EGL_CONTEXT_MAJOR_VERSION_KHR, 4,
    128         EGL_CONTEXT_MINOR_VERSION_KHR, 3,
    129         EGL_NONE
    130     };
    131     ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, attribs);
    132     if (ctx == EGL_NO_CONTEXT) {
    133         fprintf(stderr, "eglCreateContext(GL 3.2) failed.\n");
    134         exit(1);
    135     }
    136 
    137     if (!eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
    138         fprintf(stderr, "eglMakeCurrent failed.\n");
    139         exit(1);
    140     }
    141 }
    142 
    143 static char *
    144 read_file(const char *filename)
    145 {
    146     FILE *f = fopen(filename, "r");
    147     if (!f) {
    148         fprintf(stderr, "Can't open file: %s\n", filename);
    149         exit(1);
    150     }
    151 
    152     fseek(f, 0, SEEK_END);
    153     int filesize = ftell(f);
    154     fseek(f, 0, SEEK_SET);
    155 
    156     char *input = (char*)malloc(filesize + 1);
    157     if (!input) {
    158         fprintf(stderr, "malloc failed\n");
    159         exit(1);
    160     }
    161 
    162     if (fread(input, filesize, 1, f) != 1) {
    163         fprintf(stderr, "fread failed\n");
    164         exit(1);
    165     }
    166     fclose(f);
    167 
    168     input[filesize] = 0;
    169     return input;
    170 }
    171 
    172 static void addenv(const char *name, const char *value)
    173 {
    174     const char *orig = getenv(name);
    175     if (orig) {
    176         char *newval;
    177         (void)!asprintf(&newval, "%s,%s", orig, value);
    178         setenv(name, newval, 1);
    179         free(newval);
    180     } else {
    181         setenv(name, value, 1);
    182     }
    183 }
    184 
    185 int
    186 main(int argc, char **argv)
    187 {
    188     const char *filename = NULL;
    189 
    190     for (int i = 1; i < argc; i++) {
    191         if (strstr(argv[i], "-mcpu=") == argv[i]) {
    192             setenv("SI_FORCE_FAMILY", argv[i] + 6, 1);
    193         } else if (filename == NULL) {
    194             filename = argv[i];
    195         } else {
    196             if (strcmp(argv[i], "--help") != 0 && strcmp(argv[i], "-h") != 0)
    197                 fprintf(stderr, "Unknown option: %s\n\n", argv[i]);
    198 
    199             fprintf(stderr, "Usage: amdgcn_glslc -mcpu=[chip name] [glsl filename]\n");
    200             return 1;
    201         }
    202     }
    203 
    204     if (filename == NULL) {
    205         fprintf(stderr, "No filename specified.\n");
    206         return 1;
    207     }
    208 
    209     addenv("R600_DEBUG", "precompile,vs,tcs,tes,gs,ps,cs,noir,notgsi");
    210 
    211     create_gl_core_context();
    212 
    213     /* Read the source. */
    214     char *input = read_file(filename);
    215 
    216     /* Comment out lines beginning with ; (FileCheck prefix). */
    217     if (input[0] == ';')
    218         memcpy(input, "//", 2);
    219 
    220     char *s = input;
    221     while (s = strstr(s, "\n;"))
    222         memcpy(s + 1, "//", 2);
    223 
    224     s = input;
    225     while (s && (s = strstr(s, "#shader "))) {
    226         char type_str[16], name[128];
    227         GLenum type;
    228 
    229         /* If #shader is not at the beginning of the line. */
    230         if (s != input && s[-1] != '\n' && s[-1] != 0) {
    231             s = strstr(s, "\n");
    232             continue;
    233         }
    234 
    235         /* Parse the #shader directive. */
    236         if (sscanf(s + 8, "%s %s", type_str, name) != 2) {
    237             fprintf(stderr, "Cannot parse #shader directive.\n");
    238             continue;
    239         }
    240 
    241         if (!strcmp(type_str, "vs"))
    242             type = GL_VERTEX_SHADER;
    243         else if (!strcmp(type_str, "tcs"))
    244             type = GL_TESS_CONTROL_SHADER;
    245         else if (!strcmp(type_str, "tes"))
    246             type = GL_TESS_EVALUATION_SHADER;
    247         else if (!strcmp(type_str, "gs"))
    248             type = GL_GEOMETRY_SHADER;
    249         else if (!strcmp(type_str, "fs"))
    250             type = GL_FRAGMENT_SHADER;
    251         else if (!strcmp(type_str, "cs"))
    252             type = GL_COMPUTE_SHADER;
    253 
    254         /* Go the next line. */
    255         s = strstr(s, "\n");
    256         if (!s)
    257             break;
    258         s++;
    259 
    260         const char *source = s;
    261 
    262         /* Cut the shader source at the end. */
    263         s = strstr(s, "#shader");
    264         if (s && s[-1] == '\n')
    265             s[-1] = 0;
    266 
    267         /* Compile the shader. */
    268         printf("@%s:\n", name);
    269 
    270         /* Redirect stderr to stdout for the compiler. */
    271         FILE *stderr_original = stderr;
    272         stderr = stdout;
    273         GLuint prog = glCreateShaderProgramv(type, 1, &source);
    274         stderr = stderr_original;
    275 
    276         GLint linked;
    277         glGetProgramiv(prog, GL_LINK_STATUS, &linked);
    278 
    279         if (!linked) {
    280             char log[4096];
    281             GLsizei length;
    282 
    283             glGetProgramInfoLog(prog, sizeof(log), &length, log);
    284             fprintf(stderr, "ERROR: Compile failure:\n\n%s\n%s\n",
    285                     source, log);
    286             return 1;
    287         }
    288 
    289         glDeleteProgram(prog);
    290     }
    291     return 0;
    292 }
    293