2 * Copyright © 2014 Intel Corporation
3 * Copyright © 2016 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 * This program reads and compiles multiple GLSL shaders from one source file.
28 * Each shader must begin with the #shader directive. Syntax:
29 * #shader [vs|tcs|tes|gs|ps|cs] [name]
31 * The shader name is printed, followed by the stderr output from
32 * glCreateShaderProgramv. (radeonsi prints the shader disassembly there)
34 * The optional parameter -mcpu=[processor] forces radeonsi to compile for
35 * the specified GPU processor. (e.g. tahiti, bonaire, tonga)
37 * The program doesn't check if the underlying driver is really radeonsi.
38 * OpenGL 4.3 Core profile is required.
50 #include <epoxy/egl.h>
53 #define unlikely(x) __builtin_expect(!!(x), 0)
54 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
57 static EGLDisplay egl_dpy
;
58 static EGLContext ctx
;
61 create_gl_core_context()
63 const char *client_extensions
= eglQueryString(EGL_NO_DISPLAY
,
65 if (!client_extensions
) {
66 fprintf(stderr
, "ERROR: Missing EGL_EXT_client_extensions\n");
70 if (!strstr(client_extensions
, "EGL_MESA_platform_gbm")) {
71 fprintf(stderr
, "ERROR: Missing EGL_MESA_platform_gbm\n");
75 fd
= open("/dev/dri/renderD128", O_RDWR
);
76 if (unlikely(fd
< 0)) {
77 fprintf(stderr
, "ERROR: Couldn't open /dev/dri/renderD128\n");
81 struct gbm_device
*gbm
= gbm_create_device(fd
);
82 if (unlikely(gbm
== NULL
)) {
83 fprintf(stderr
, "ERROR: Couldn't create gbm device\n");
87 egl_dpy
= eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA
,
89 if (unlikely(egl_dpy
== EGL_NO_DISPLAY
)) {
90 fprintf(stderr
, "ERROR: eglGetDisplay() failed\n");
94 if (unlikely(!eglInitialize(egl_dpy
, NULL
, NULL
))) {
95 fprintf(stderr
, "ERROR: eglInitialize() failed\n");
99 static const char *egl_extension
[] = {
100 "EGL_KHR_create_context",
101 "EGL_KHR_surfaceless_context"
103 const char *extension_string
= eglQueryString(egl_dpy
, EGL_EXTENSIONS
);
104 for (int i
= 0; i
< ARRAY_SIZE(egl_extension
); i
++) {
105 if (strstr(extension_string
, egl_extension
[i
]) == NULL
) {
106 fprintf(stderr
, "ERROR: Missing %s\n", egl_extension
[i
]);
111 static const EGLint config_attribs
[] = {
112 EGL_RENDERABLE_TYPE
, EGL_OPENGL_BIT
,
118 if (!eglChooseConfig(egl_dpy
, config_attribs
, &cfg
, 1, &count
) ||
120 fprintf(stderr
, "ERROR: eglChooseConfig() failed\n");
123 eglBindAPI(EGL_OPENGL_API
);
125 static const EGLint attribs
[] = {
126 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
,
127 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
,
128 EGL_CONTEXT_MAJOR_VERSION_KHR
, 4,
129 EGL_CONTEXT_MINOR_VERSION_KHR
, 3,
132 ctx
= eglCreateContext(egl_dpy
, cfg
, EGL_NO_CONTEXT
, attribs
);
133 if (ctx
== EGL_NO_CONTEXT
) {
134 fprintf(stderr
, "eglCreateContext(GL 3.2) failed.\n");
138 if (!eglMakeCurrent(egl_dpy
, EGL_NO_SURFACE
, EGL_NO_SURFACE
, ctx
)) {
139 fprintf(stderr
, "eglMakeCurrent failed.\n");
145 read_file(const char *filename
)
147 FILE *f
= fopen(filename
, "r");
149 fprintf(stderr
, "Can't open file: %s\n", filename
);
153 fseek(f
, 0, SEEK_END
);
154 int filesize
= ftell(f
);
155 fseek(f
, 0, SEEK_SET
);
157 char *input
= (char*)malloc(filesize
+ 1);
159 fprintf(stderr
, "malloc failed\n");
163 if (fread(input
, filesize
, 1, f
) != 1) {
164 fprintf(stderr
, "fread failed\n");
173 static void addenv(const char *name
, const char *value
)
175 const char *orig
= getenv(name
);
178 (void)!asprintf(&newval
, "%s,%s", orig
, value
);
179 setenv(name
, newval
, 1);
182 setenv(name
, value
, 1);
187 main(int argc
, char **argv
)
189 const char *filename
= NULL
;
191 for (int i
= 1; i
< argc
; i
++) {
192 if (strstr(argv
[i
], "-mcpu=") == argv
[i
]) {
193 setenv("SI_FORCE_FAMILY", argv
[i
] + 6, 1);
194 } else if (filename
== NULL
) {
197 if (strcmp(argv
[i
], "--help") != 0 && strcmp(argv
[i
], "-h") != 0)
198 fprintf(stderr
, "Unknown option: %s\n\n", argv
[i
]);
200 fprintf(stderr
, "Usage: amdgcn_glslc -mcpu=[chip name] [glsl filename]\n");
205 if (filename
== NULL
) {
206 fprintf(stderr
, "No filename specified.\n");
210 addenv("R600_DEBUG", "precompile,vs,tcs,tes,gs,ps,cs,noir,notgsi");
212 create_gl_core_context();
214 /* Read the source. */
215 char *input
= read_file(filename
);
217 /* Comment out lines beginning with ; (FileCheck prefix). */
219 memcpy(input
, "//", 2);
222 while (s
= strstr(s
, "\n;"))
223 memcpy(s
+ 1, "//", 2);
226 while (s
&& (s
= strstr(s
, "#shader "))) {
227 char type_str
[16], name
[128];
230 /* If #shader is not at the beginning of the line. */
231 if (s
!= input
&& s
[-1] != '\n' && s
[-1] != 0) {
236 /* Parse the #shader directive. */
237 if (sscanf(s
+ 8, "%s %s", type_str
, name
) != 2) {
238 fprintf(stderr
, "Cannot parse #shader directive.\n");
242 if (!strcmp(type_str
, "vs"))
243 type
= GL_VERTEX_SHADER
;
244 else if (!strcmp(type_str
, "tcs"))
245 type
= GL_TESS_CONTROL_SHADER
;
246 else if (!strcmp(type_str
, "tes"))
247 type
= GL_TESS_EVALUATION_SHADER
;
248 else if (!strcmp(type_str
, "gs"))
249 type
= GL_GEOMETRY_SHADER
;
250 else if (!strcmp(type_str
, "fs"))
251 type
= GL_FRAGMENT_SHADER
;
252 else if (!strcmp(type_str
, "cs"))
253 type
= GL_COMPUTE_SHADER
;
255 /* Go the next line. */
261 const char *source
= s
;
263 /* Cut the shader source at the end. */
264 s
= strstr(s
, "#shader");
265 if (s
&& s
[-1] == '\n')
268 /* Compile the shader. */
269 printf("@%s:\n", name
);
271 /* Redirect stderr to stdout for the compiler. */
272 FILE *stderr_original
= stderr
;
274 GLuint prog
= glCreateShaderProgramv(type
, 1, &source
);
275 stderr
= stderr_original
;
278 glGetProgramiv(prog
, GL_LINK_STATUS
, &linked
);
284 glGetProgramInfoLog(prog
, sizeof(log
), &length
, log
);
285 fprintf(stderr
, "ERROR: Compile failure:\n\n%s\n%s\n",
290 glDeleteProgram(prog
);