xref: /openbmc/qemu/ui/shader.c (revision e2fb7d8aa218256793df99571d16f92074258447)
1  /*
2   * QEMU opengl shader helper functions
3   *
4   * Copyright (c) 2014 Red Hat
5   *
6   * Authors:
7   *    Gerd Hoffmann <kraxel@redhat.com>
8   *
9   * Permission is hereby granted, free of charge, to any person obtaining a copy
10   * of this software and associated documentation files (the "Software"), to deal
11   * in the Software without restriction, including without limitation the rights
12   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13   * copies of the Software, and to permit persons to whom the Software is
14   * furnished to do so, subject to the following conditions:
15   *
16   * The above copyright notice and this permission notice shall be included in
17   * all copies or substantial portions of the Software.
18   *
19   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25   * THE SOFTWARE.
26   */
27  #include "qemu/osdep.h"
28  #include "ui/shader.h"
29  
30  #include "ui/shader/texture-blit-vert.h"
31  #include "ui/shader/texture-blit-flip-vert.h"
32  #include "ui/shader/texture-blit-frag.h"
33  
34  struct QemuGLShader {
35      GLint texture_blit_prog;
36      GLint texture_blit_flip_prog;
37      GLint texture_blit_vao;
38  };
39  
40  /* ---------------------------------------------------------------------- */
41  
qemu_gl_init_texture_blit(GLint texture_blit_prog)42  static GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
43  {
44      static const GLfloat in_position[] = {
45          -1, -1,
46          1,  -1,
47          -1,  1,
48          1,   1,
49      };
50      GLint l_position;
51      GLuint vao, buffer;
52  
53      glGenVertexArrays(1, &vao);
54      glBindVertexArray(vao);
55  
56      /* this is the VBO that holds the vertex data */
57      glGenBuffers(1, &buffer);
58      glBindBuffer(GL_ARRAY_BUFFER, buffer);
59      glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position,
60                   GL_STATIC_DRAW);
61  
62      l_position = glGetAttribLocation(texture_blit_prog, "in_position");
63      glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
64      glEnableVertexAttribArray(l_position);
65  
66      glBindBuffer(GL_ARRAY_BUFFER, 0);
67      glBindVertexArray(0);
68  
69      return vao;
70  }
71  
qemu_gl_run_texture_blit(QemuGLShader * gls,bool flip)72  void qemu_gl_run_texture_blit(QemuGLShader *gls, bool flip)
73  {
74      glUseProgram(flip
75                   ? gls->texture_blit_flip_prog
76                   : gls->texture_blit_prog);
77      glBindVertexArray(gls->texture_blit_vao);
78      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
79  }
80  
81  /* ---------------------------------------------------------------------- */
82  
qemu_gl_create_compile_shader(GLenum type,const GLchar * src)83  static GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src)
84  {
85      GLuint shader;
86      GLint status, length;
87      char *errmsg;
88  
89      shader = glCreateShader(type);
90      glShaderSource(shader, 1, &src, 0);
91      glCompileShader(shader);
92  
93      glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
94      if (!status) {
95          glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
96          errmsg = g_malloc(length);
97          glGetShaderInfoLog(shader, length, &length, errmsg);
98          fprintf(stderr, "%s: compile %s error\n%s\n", __func__,
99                  (type == GL_VERTEX_SHADER) ? "vertex" : "fragment",
100                  errmsg);
101          g_free(errmsg);
102          return 0;
103      }
104      return shader;
105  }
106  
qemu_gl_create_link_program(GLuint vert,GLuint frag)107  static GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag)
108  {
109      GLuint program;
110      GLint status, length;
111      char *errmsg;
112  
113      program = glCreateProgram();
114      glAttachShader(program, vert);
115      glAttachShader(program, frag);
116      glLinkProgram(program);
117  
118      glGetProgramiv(program, GL_LINK_STATUS, &status);
119      if (!status) {
120          glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
121          errmsg = g_malloc(length);
122          glGetProgramInfoLog(program, length, &length, errmsg);
123          fprintf(stderr, "%s: link program: %s\n", __func__, errmsg);
124          g_free(errmsg);
125          return 0;
126      }
127      return program;
128  }
129  
qemu_gl_create_compile_link_program(const GLchar * vert_src,const GLchar * frag_src)130  static GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
131                                                    const GLchar *frag_src)
132  {
133      GLuint vert_shader, frag_shader, program = 0;
134  
135      vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src);
136      frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src);
137      if (!vert_shader || !frag_shader) {
138          goto end;
139      }
140  
141      program = qemu_gl_create_link_program(vert_shader, frag_shader);
142  
143  end:
144      glDeleteShader(vert_shader);
145      glDeleteShader(frag_shader);
146  
147      return program;
148  }
149  
150  /* ---------------------------------------------------------------------- */
151  
qemu_gl_init_shader(void)152  QemuGLShader *qemu_gl_init_shader(void)
153  {
154      QemuGLShader *gls = g_new0(QemuGLShader, 1);
155  
156      gls->texture_blit_prog = qemu_gl_create_compile_link_program
157          (texture_blit_vert_src, texture_blit_frag_src);
158      gls->texture_blit_flip_prog = qemu_gl_create_compile_link_program
159          (texture_blit_flip_vert_src, texture_blit_frag_src);
160      if (!gls->texture_blit_prog || !gls->texture_blit_flip_prog) {
161          exit(1);
162      }
163  
164      gls->texture_blit_vao =
165          qemu_gl_init_texture_blit(gls->texture_blit_prog);
166  
167      return gls;
168  }
169  
qemu_gl_fini_shader(QemuGLShader * gls)170  void qemu_gl_fini_shader(QemuGLShader *gls)
171  {
172      if (!gls) {
173          return;
174      }
175      glDeleteProgram(gls->texture_blit_prog);
176      glDeleteProgram(gls->texture_blit_flip_prog);
177      glDeleteProgram(gls->texture_blit_vao);
178      g_free(gls);
179  }
180