Commits (2)
  • Kenneth Graunke's avatar
    run: Add separate shader objects support. · 6635bf45
    Kenneth Graunke authored
    With this patch, if a .shader_test file contains
    then we'll set GL_PROGRAM_SEPARABLE to compile the shaders into separate
    shader objects.  This prevents the linker from removing unused inputs
    and outputs.  Drivers may also choose to lay out interfaces of SSO
    programs differently, resulting in different code.
    - Actually initialize use_separate_shader_objects
    - Fix memcmp length parameter (thanks to Matt)
    - Search for "SSO ENABLED" instead of "GL_ARB_separate_shader_objects",
      to match what Timothy did in shader_runner.
    - Use GL_PROGRAM_SEPARABLE (suggested by Tapani).  This allows
      multi-stage SSO programs to optimize internal interfaces, while
      still making the end-stages separable.
  • Kenneth Graunke's avatar
    run: Mark shaders with only one stage as separable. · d74b3c25
    Kenneth Graunke authored
    There are a couple cases where a single shader might happen:
    - compute shaders
      (only one stage, no inputs and outputs; separable shouldn't matter)
    - vertex shaders with transform feedback
      (we want to retain outputs, but transform feedback varyings are
       specified via the API, not the shader - setting SSO fixes this)
    - old shader_test files captured before we started adding "SSO ENABLED".
    In any case, it seems harmless or beneficial to enable SSO for all
    .shader_test files containing a single shader.
......@@ -73,12 +73,14 @@ static struct shader *
get_shaders(const struct context_info *core, const struct context_info *compat,
const char *text, size_t text_size,
enum shader_type *type, unsigned *num_shaders,
bool *use_separate_shader_objects,
const char *shader_name)
static const char *req = "[require]";
static const char *glsl_req = "\nGLSL >= ";
static const char *fp_req = "\nGL_ARB_fragment_program";
static const char *vp_req = "\nGL_ARB_vertex_program";
static const char *sso_req = "SSO ENABLED";
static const char *gs = "geometry shader]\n";
static const char *fs = "fragment ";
static const char *vs = "vertex ";
......@@ -90,6 +92,8 @@ get_shaders(const struct context_info *core, const struct context_info *compat,
static const char *test = "test]\n";
const char *end_text = text + text_size;
*use_separate_shader_objects = false;
/* Find the [require] block and parse it first. */
text = memmem(text, end_text - text, req, strlen(req)) + strlen(req);
......@@ -137,6 +141,9 @@ get_shaders(const struct context_info *core, const struct context_info *compat,
shader_name, (int)(newline - extension_text), extension_text);
return NULL;
if (memcmp(extension_text, sso_req, strlen(sso_req)) == 0) {
*use_separate_shader_objects = true;
/* Find the shaders. */
......@@ -606,9 +613,11 @@ main(int argc, char **argv)
enum shader_type type;
unsigned num_shaders;
bool use_separate_shader_objects;
struct shader *shader = get_shaders(&core, &compat,
text, shader_test[i].filesize,
&type, &num_shaders,
if (unlikely(shader == NULL)) {
......@@ -624,9 +633,18 @@ main(int argc, char **argv)
ctx_is_core = type == TYPE_CORE;
/* If there's only one shader, mark it separable so inputs
* and outputs aren't eliminated.
if (num_shaders == 1)
use_separate_shader_objects = true;
if (type == TYPE_CORE || type == TYPE_COMPAT) {
GLuint prog = glCreateProgram();
if (use_separate_shader_objects)
glProgramParameteri(prog, GL_PROGRAM_SEPARABLE, GL_TRUE);
for (unsigned i = 0; i < num_shaders; i++) {
GLuint s = glCreateShader(shader[i].type);
glShaderSource(s, 1, &shader[i].text, &shader[i].length);