<div dir="ltr">On 4 September 2013 12:57, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org" target="_blank">idr@freedesktop.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">From: Gregory Hainaut <<a href="mailto:gregory.hainaut@gmail.com" target="_blank">gregory.hainaut@gmail.com</a>><br>

<br>
the goal is to test the state mix of glUseProgram /<br>
glBindProgramPipeline / glActiveProgram.<br>
<br>
Ian R. quote:<br>
    "In this case, either the UseProgram state or the<br>
    BindProgramPipeline state.  If UseProgram sets a non-zero program,<br>
    that state is used.  Otherwise the BindProgramPipeline state is<br>
    used.....In this case, I think AMD's behavior is incorrect."<br></blockquote><div><br></div><div>Could we have some additional context on this quote (what case are you talking about?  What behaviour of AMD's is incorrect?)<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Note: Nvidia seems to be fine.<br>
<br>
V4:<br>
* split into a separate commit<br>
* Merge the 2 vertex shaders with the help of the __VERSION__ macro<br>
* Properly set shader version with asprintf<br>
* Use standard bool<br>
* Split test into subtest<br>
* Fix expected of GL_PROGRAM_PIPELINE_BINDING (based on nvidia behavior)<br>
<br>
V5 (idr):<br>
<br>
* Expect GL_PROGRAM_PIPELINE_BINDING to still be pipe when a<br>
  non-separable program is also bound (via glUseProgram).  After<br>
  discussions in Khronos, that was determined to be the correct<br>
  behavior.  Fix NVIDIA drivers should be available soon.<br>
* Don't test glUseProgramStages with a non-separable program.  There is<br>
  a separate test for that now.<br>
* Use 'pass = foo() && pass;' idiom instead of 'pass &= foo();'.  C's<br>
  short-circuit evaulation rules cause these to be different.<br>
* Use piglit_build_simple_program for non-separable shader program.<br>
* #extension is only necessary to use layout qualifiers, so remove it.<br>
* s/GLboolean/bool/g<br>
* Produce no output with -auto.<br>
* Use descriptive names for subtests.<br>
* Add test to CMakeLists.gl.txt.<br>
* Trivial reformatting.<br>
<br>
Note: vertex shader doesn't work with FGLRX. It would require GLSL150<br>
but that mean you can't use fixed pipeline anymore...<br>
<br>
Reviewed-by: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com" target="_blank">ian.d.romanick@intel.com</a>><br>
---<br>
 tests/all.tests                                    |   1 +<br>
 .../arb_separate_shader_objects/CMakeLists.gl.txt  |   1 +<br>
 .../mix_pipeline_useprogram.c                      | 358 +++++++++++++++++++++<br>
 3 files changed, 360 insertions(+)<br>
 create mode 100644 tests/spec/arb_separate_shader_objects/mix_pipeline_useprogram.c<br>
<br>
diff --git a/tests/all.tests b/tests/all.tests<br>
index 346556d..bfd6025 100644<br>
--- a/tests/all.tests<br>
+++ b/tests/all.tests<br>
@@ -1240,6 +1240,7 @@ spec['ARB_separate_shader_objects'] = arb_separate_shader_objects<br>
 arb_separate_shader_objects['GetProgramPipelineiv'] = concurrent_test('arb_separate_shader_object-GetProgramPipelineiv')<br>
 arb_separate_shader_objects['IsProgramPipeline'] = concurrent_test('arb_separate_shader_object-IsProgramPipeline')<br>
 arb_separate_shader_objects['UseProgramStages - non-separable program'] = concurrent_test('arb_separate_shader_object-UseProgramStages-non-separable')<br>
+arb_separate_shader_objects['Mix BindProgramPipeline and UseProgram'] = concurrent_test('arb_separate_shader_object-mix_pipeline_useprogram')<br>
<br>
 # Group ARB_sampler_objects<br>
 arb_sampler_objects = Group()<br>
diff --git a/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt b/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt<br>
index 3397b4d..70ef99a 100644<br>
--- a/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt<br>
+++ b/tests/spec/arb_separate_shader_objects/CMakeLists.gl.txt<br>
@@ -11,4 +11,5 @@ link_libraries (<br>
<br>
 piglit_add_executable (arb_separate_shader_object-GetProgramPipelineiv GetProgramPipelineiv.c)<br>
 piglit_add_executable (arb_separate_shader_object-IsProgramPipeline IsProgramPipeline.c)<br>
+piglit_add_executable (arb_separate_shader_object-mix_pipeline_useprogram mix_pipeline_useprogram.c)<br>
 piglit_add_executable (arb_separate_shader_object-UseProgramStages-non-separable UseProgramStages-non-separable.c)<br>
diff --git a/tests/spec/arb_separate_shader_objects/mix_pipeline_useprogram.c b/tests/spec/arb_separate_shader_objects/mix_pipeline_useprogram.c<br>
new file mode 100644<br>
index 0000000..8761a0e<br>
--- /dev/null<br>
+++ b/tests/spec/arb_separate_shader_objects/mix_pipeline_useprogram.c<br>
@@ -0,0 +1,358 @@<br>
+/*<br>
+ * Copyright © 2013 Gregory Hainaut <<a href="mailto:gregory.hainaut@gmail.com" target="_blank">gregory.hainaut@gmail.com</a>><br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/**<br>
+ * \file mix_pipeline_useprogram.<br>
+ * Test mixing separable and non-separable programs in various ways.<br>
+ *<br>
+ * Section 2.11.3 (Program Objects) of the OpenGL 4.1 spec says:<br>
+ *<br>
+ *     "The executable code for an individual shader stage is taken from the<br>
+ *     current program for that stage. If there is a current program object<br>
+ *     established by UseProgram, that program is considered current for all<br>
+ *     stages. Otherwise, if there is a bound program pipeline object (see<br>
+ *     section 2.11.4), the program bound to the appropriate stage of the<br>
+ *     pipeline object is considered current. If there is no current program<br>
+ *     object or bound program pipeline object, no program is current for any<br>
+ *     stage."<br>
+<br>
+ * Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec says:<br>
+ *<br>
+ *     "If no current program object has been established by UseProgram, the<br>
+ *     program objects used for each shader stage and for uniform updates are<br>
+ *     taken from the bound program pipeline object, if any. If there is a<br>
+ *     current program object established by UseProgram, the bound program<br>
+ *     pipeline object has no effect on rendering or uniform updates. When a<br>
+ *     bound program pipeline object is used for rendering, individual shader<br>
+ *     executables are taken from its program objects as described in the<br>
+ *     discussion of UseProgram in section 2.11.3)."<br>
+ *<br>
+ * Section 2.11.7 (Uniform Variables) of the OpenGL 4.1 spec says:<br>
+ *<br>
+ *     "If a non-zero program object is bound by UseProgram, it is the active<br>
+ *     program object whose uniforms are updated by these commands. If no<br>
+ *     program object is bound using UseProgram, the active program object of<br>
+ *     the current program pipeline object set by ActiveShaderProgram is the<br>
+ *     active program object. If the current program pipeline object has no<br>
+ *     active program or there is no current program pipeline object, then<br>
+ *     there is no active program."<br>
+ *<br>
+ * Note that with these rules, it's not possible to mix program objects bound<br>
+ * to the context with program objects bound to a program pipeline object; if<br>
+ * any program is bound to the context, the current pipeline object is<br>
+ * ignored.<br>
+ */<br>
+#include "piglit-util-gl-common.h"<br>
+<br>
+PIGLIT_GL_TEST_CONFIG_BEGIN<br>
+<br>
+       config.supports_gl_compat_version = 10;<br>
+<br>
+       config.window_width = 32;<br>
+       config.window_height = 32;<br>
+<br>
+PIGLIT_GL_TEST_CONFIG_END<br>
+<br>
+static GLuint prog;<br>
+static GLuint pipe;<br>
+static bool pass = true;<br>
+static bool subtest = true;<br>
+<br>
+static bool<br>
+check(GLenum pname, GLint expected)<br></blockquote><div><br></div><div>This is a nit-pick, but several of the tests in this series include functions with names like "check", and I'm having trouble keeping track of what is checked by each one.  Could we rename this to something like "check_Integerv"?<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+{<br>
+       GLint value = 0;<br>
+       glGetIntegerv(pname, &value);<br>
+<br>
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;<br>
+       if (value != expected) {<br>
+               fprintf(stderr, "Failed to get %s expected %d got %d\n",<br>
+                       piglit_get_gl_enum_name(pname), expected, value);<br>
+               return false;<br>
+       } else {<br>
+               return true;<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+bind_program(bool enable)<br>
+{<br>
+       if (enable) {<br>
+               glUseProgram(prog);<br>
+               if (!piglit_automatic)<br>
+                       printf("Enable monolithic program\n");<br>
+               subtest = check(GL_CURRENT_PROGRAM, prog) && subtest;<br>
+       } else {<br>
+               glUseProgram(0);<br>
+               if (!piglit_automatic)<br>
+                       printf("Disable monolithic program\n");<br>
+               subtest = check(GL_CURRENT_PROGRAM, 0) && subtest;<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+bind_pipeline(bool enable)<br>
+{<br>
+       if (enable) {<br>
+               glBindProgramPipeline(pipe);<br>
+               if (!piglit_automatic)<br>
+                       printf("Bind pipeline\n");<br>
+       } else {<br>
+               glBindProgramPipeline(0);<br>
+               if (!piglit_automatic)<br>
+                       printf("Unbind pipeline\n");<br>
+       }<br>
+}<br></blockquote><div><br></div><div>It seems inconsistent that bind_program calls check(GL_CURRENT_PROGRAM) but bind_pipeline doesn't call check(GL_PROGRAM_PIPELINE_BINDING).  But I'm not entirely sure what kinds of bugs we're trying to guard against with these checks, so I don't really have a good suggestion for what to do instead.<br>
<br>Personally, I'd be tempted to remove all the calls to check() entirely, since they seem kind of tangential to the primary purpose of the test.  That would make the printf's unnecessary, at which point we could just replace bind_program and bind_pipeline with direct calls to glUseProgram() and glBindProgramPipeline(), which would make the test a whole lot easier to follow.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+static bool<br>
+draw(float expected[4])<br>
+{<br>
+       piglit_draw_rect(-1, -1, 2, 2);<br>
+       return piglit_probe_rect_rgba(0, 0, piglit_width, piglit_height,<br>
+                                     expected);<br>
+}<br>
+<br>
+static bool<br>
+set_and_check_uniform(GLint program, float expected)<br>
+{<br>
+       float value;<br>
+       glUniform1f(0, expected);<br>
+       glGetUniformfv(program, 0, &value);<br>
+       if (value != expected) {<br>
+               fprintf(stderr,<br>
+                       "Failed to get uniform value of %d, expected %f, "<br>
+                       "got %f\n",<br>
+                       program, expected, value);<br>
+               return false;<br>
+       }<br>
+       return true;<br>
+}<br>
+<br>
+static void<br>
+report_subtest(const char* msg)<br>
+{<br>
+       piglit_report_subtest_result(subtest ? PIGLIT_PASS : PIGLIT_FAIL, msg);<br>
+<br>
+       pass = subtest && pass;<br>
+       subtest = true;<br></blockquote><div><br></div><div>I find it really hard to keep track of the use of the "pass" and "subtest" globals in this test.  Could we switch to an approach where each function that needs to keep track of pass/fail has a local "pass" boolean, which it initializes to true, sets to false in the event of failure, and returns at the end of the function?  We do that in a lot of other tests and I've never had trouble following that. <br>
<br></div><div>Side question, since I've never written a test using subtests before: is it necessary for the test to keep track of an aggregate pass/fail state, and report that correctly at the conclusion of the test, or is it ok to report subtest results and then always return PIGLIT_PASS from piglit_display()?  I'm assuming it's the former, although I wish it were the latter :)<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<br></blockquote><div><br></div><div>Would you have any objection to moving piglit_init before piglit_display in this test?  A long time ago I started doing that in my piglit tests because I usually find it easier to follow the logic of piglit_dispaly once I've seen piglit_init.  That seems particularly true of this test, since the shader source code is contained in piglit_init.<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+enum piglit_result<br>
+piglit_display(void)<br>
+{<br>
+       GLint active_shader_pipe;<br>
+       GLint uniform_loc_pipe;<br>
+       GLint uniform_loc_prog;<br>
+       float red[4] = {1.0, 0.0, 0.0, 1.0};<br>
+       float green[4] = {0.0, 1.0, 0.0, 1.0};<br>
+       float blue[4] = {0.0, 0.0, 1.0, 1.0};<br>
+       float gb[4] = {0.0, 1.0, 1.0, 1.0};<br>
+<br>
+       glGetProgramPipelineiv(pipe, GL_ACTIVE_PROGRAM, &active_shader_pipe);<br>
+       uniform_loc_pipe = glGetUniformLocation(active_shader_pipe, "blue");<br>
+       uniform_loc_prog = glGetUniformLocation(prog, "blue");<br>
+       /* otherwise it is difficult which program is really updated */<br>
+       assert(uniform_loc_prog == 0);<br>
+       assert(uniform_loc_pipe == 0);<br></blockquote><div><br></div><div>This seems really dodgy to me.  My understanding is that OpenGL makes no guarantees as to where any particular uniform is located, even in the circumstance we have here where only one uniform exists.<br>

<br>IMHO we should write the test so that (a) if the "blue" uniform gets assigned the same nonzero location in both prog and active_shader_pipe, the test is still just as effective, and (b) if the "blue" uniform gets assigned different locations in prog and active_shader_pipe, the test still passes (but it's ok if it's a less mean test in this case).  I think all that would be required is to add a "location" argument to set_and_check_uniform, and pass either uniform_loc_prog or uniform_loc_pipe to it at each call site, as appropriate.<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       /* wrong setup: stop here */<br>
+       if (!pass)<br>
+               return PIGLIT_FAIL;<br>
+<br>
+       /* Set up fixed function to draw blue if we lose our shader. */<br>
+       glColor4f(0.0, 0.0, 1.0, 1.0);<br>
+<br>
+       /* TEST 1: BindPipeline after UseProgram */<br>
+       if (!piglit_automatic)<br>
+               printf("glUseProgram, then glBindPipeline...\n");<br></blockquote><div><br></div><div>It's confusing that so many of the comments and printfs in this test refer to the non-existent function "glBindPipeline", when the actual GL function is glBindProgramPipeline.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+       bind_program(true);<br>
+       subtest = set_and_check_uniform(prog, 1.0) && subtest;<br>
+       bind_pipeline(true);<br>
+       /* It must ignore the pipeline */<br>
+       subtest = set_and_check_uniform(prog, 0.0) && subtest; <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+       /* But the pipeline is attached to the binding point */<br>
+       subtest = check(GL_PROGRAM_PIPELINE_BINDING, pipe) && subtest;<br>
+<br>
+       /* UseProgram rendering */<br>
+       subtest = draw(red) && subtest;<br>
+<br>
+       report_subtest("glUseProgram, then glBindPipeline");<br></blockquote><div><br></div><div>I would find this a lot easier to read if each subtest were contained in its own function.  That, combined with my suggestion above about making the pass/fail booleans local, would have the advantage of avoiding the need for separate "subtest" and "pass" booleans--each subtest would have its own "pass" boolean, which it would report to piglit_report_subtest_result() and then return to piglit_display().  piglit_display() would keep track of the aggregate "pass" boolean for the whole test.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       /* TEST 2: BindPipeline without UseProgram */<br>
+       if (!piglit_automatic)<br>
+               printf("glBindPipeline without glUseProgram...\n");<br>
+       bind_program(false);<br>
+       bind_pipeline(true);<br>
+       subtest = set_and_check_uniform(active_shader_pipe, 1.0) && subtest;<br>
+       subtest = check(GL_PROGRAM_PIPELINE_BINDING, pipe) && subtest;<br>
+<br>
+       /* Pipeline rendering  */<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       report_subtest("glBindPipeline without glUseProgram");<br>
+<br>
+       /* TEST 3: UseProgram after BindPipeline */<br>
+       if (!piglit_automatic)<br>
+               printf("glBindPipeline, then glUseProgram...\n");<br>
+       bind_program(true);<br>
+       subtest = check(GL_PROGRAM_PIPELINE_BINDING, pipe) && subtest;<br>
+<br>
+       report_subtest("glBindPipeline, then glUseProgram");<br></blockquote><div><br></div>Shouldn't this call to report_subtest() be after the call to draw(red) that follows?  As written, a failure in the draw call will be classified as a failure in subtest 4.<br>
</div><div class="gmail_quote"> <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       /* UseProgram rendering */<br>
+       subtest = draw(red) && subtest;<br></blockquote><div><br><div>It would also be nice if each subtest started and ended in a GL 
state where the current program and the currently bound pipeline are 
both 0, and if subtests didn't rely on uniform settings from previous subtests.  It took me a long time to reassure myself that subtest 3 was correct, because it 
relies implicitly on the fact that (a) subtest 2 leaves the pipeline bound, and (b) subtest 1 leaves 0.0 in prog's value of the "blue" uniform.<br></div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

+<br>
+       /* TEST 4: UseProgram(0) after BindPipeline */<br>
+       if (!piglit_automatic)<br>
+               printf("glBindPipeline, then glUseProgram(0)...\n");<br>
+       bind_program(false);<br>
+       bind_pipeline(true);<br></blockquote><div><br></div><div>The reliance on previous state is particularly confusing here, since it looks like we are calling UseProgram(0) *before* BindProgramPipeline.  To understand that the test is correct, you have to look all the way back to subtest 2 and see that it leaves the program pipeline bound, so the call to UseProgram(0) (inside bind_program) is indeed after a call to BindProgramPipeline.  I'd far prefer to see this:<br>
<br></div><div>bind_program(true);<br>bind_pipeline(true);<br></div><div>bind_program(false);<br><br>since it clearly captures the intent of the subtest.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

+       subtest = check(GL_PROGRAM_PIPELINE_BINDING, pipe) && subtest;<br>
+<br>
+       /* Sanity check */<br>
+       /* Pipeline rendering  */<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       bind_program(false);<br>
+<br>
+       /* Pipeline rendering  */<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       bind_pipeline(true);<br>
+       subtest = check(GL_PROGRAM_PIPELINE_BINDING, pipe) && subtest;<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       report_subtest("glBindPipeline, then glUseProgram(0)");<br>
+<br>
+       /* TEST 5: like previous test but use a real program before<br>
+        * UseProgram(0)<br>
+        */<br>
+       if (!piglit_automatic)<br>
+               printf("glUseProgram, then glBindPipeline, "<br>
+                      "then glUseProgram(0)...\n");<br></blockquote><div><br></div><div>I don't understand the relationship between this summary and the test that follows it.  Based on the summary, I expect to see a call to glBindProgramPipeline(pipe) happen at a time when the current program is nonzero.  But I don't see that happening anywhere in the subtest.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+       bind_program(false);<br>
+       bind_pipeline(true);<br>
+<br>
+       /* Sanity check */<br>
+       /* Pipeline rendering  */<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       /* Set wrong uniform value */<br>
+       subtest = set_and_check_uniform(active_shader_pipe, 0.0) && subtest;<br>
+<br>
+       bind_program(true);<br>
+       bind_program(false);<br>
+<br>
+       /* Pipeline rendering: with bad uniform  */<br>
+       subtest = draw(gb) && subtest;<br>
+<br>
+       /* pipeline program must be still active */<br>
+       subtest = set_and_check_uniform(active_shader_pipe, 1.0) && subtest;<br>
+<br>
+       bind_pipeline(true);<br>
+       /* Pipeline rendering  */<br>
+       subtest = draw(green) && subtest;<br>
+<br>
+       report_subtest("glUseProgram, then glBindPipeline, "<br>
+                      "then glUseProgram(0)");<br>
+<br>
+       /* TEST 6: Sanity check */<br>
+       if (!piglit_automatic)<br>
+               printf("Final sanity test...\n");<br>
+       bind_program(false);<br>
+       bind_pipeline(false);<br>
+       /* Fixed function rendering */<br>
+       subtest = draw(blue) && subtest;<br>
+<br>
+       report_subtest("Final sanity test");<br></blockquote><div><br></div><div>The only parts of this test that rely on compatibility behaviour are the VS's use of gl_Vertex, and this final sanity test.  It seems to me that the final sanity test is tangential to the primary purpose of the test; I'd rather see this subtest removed, and gl_Vertex changed to a user-defined vertex attribute, so that we can add supports_gl_core_version to the config block.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       piglit_present_results();<br>
+<br>
+       return pass ? PIGLIT_PASS : PIGLIT_FAIL;<br>
+}<br>
+<br>
+<br>
+void<br>
+piglit_init(int argc, char **argv)<br>
+{<br>
+       GLint vs_prog;<br>
+       GLint fs_prog;<br>
+       GLint vs, fs;<br>
+       const char *vs_source =<br>
+               "#version 110\n"<br>
+               "void main()\n"<br>
+               "{\n"<br>
+               "       gl_Position = gl_Vertex;\n"<br>
+               "}\n";<br>
+       const char *fs_source_r =<br>
+               "#version 110\n"<br>
+               "uniform float blue;\n"<br>
+               "void main()\n"<br>
+               "{\n"<br>
+               "       gl_FragColor = vec4(1.0, 0.0, blue, 1.0);\n"<br>
+               "}\n";<br>
+       const char *fs_source_g =<br>
+               "#version 110\n"<br>
+               "uniform float blue;\n"<br>
+               "void main()\n"<br>
+               "{\n"<br>
+               "       gl_FragColor = vec4(0.0, 1.0, 1.0 - blue, 1.0);\n"<br>
+               "}\n";<br>
+<br>
+       pass = true;<br>
+<br>
+       piglit_require_gl_version(20);<br>
+       piglit_require_extension("GL_ARB_separate_shader_objects");<br>
+<br>
+       /* Standard program (ie not separate) */<br>
+       prog = piglit_build_simple_program(vs_source, fs_source_r);<br>
+<br>
+       /* Now create program for the pipeline program */<br>
+       vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);<br>
+       fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source_g);<br>
+<br>
+       vs_prog = glCreateProgram();<br>
+       glProgramParameteri(vs_prog, GL_PROGRAM_SEPARABLE, GL_TRUE);<br>
+       glAttachShader(vs_prog, vs);<br>
+       glLinkProgram(vs_prog);<br>
+       pass = piglit_link_check_status(vs_prog) && pass;<br>
+       glDeleteShader(vs);<br>
+<br>
+       fs_prog = glCreateProgram();<br>
+       glProgramParameteri(fs_prog, GL_PROGRAM_SEPARABLE, GL_TRUE);<br>
+       glAttachShader(fs_prog, fs);<br>
+       glLinkProgram(fs_prog);<br>
+       pass = piglit_link_check_status(fs_prog) && pass;<br>
+       glDeleteShader(fs);<br>
+<br>
+       glGenProgramPipelines(1, &pipe);<br>
+       glUseProgramStages(pipe, GL_VERTEX_SHADER_BIT, vs_prog);<br>
+       glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, fs_prog);<br>
+       glActiveShaderProgram(pipe, fs_prog);<br>
+       pass = piglit_program_pipeline_check_status(pipe) && pass;<br>
+<br>
+       pass = check(GL_PROGRAM_PIPELINE_BINDING, 0) && pass;<br>
+       pass = check(GL_CURRENT_PROGRAM, 0) && pass;<br>
+<br>
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;<br>
+}<br>
<span><font color="#888888">--<br>
1.8.1.4<br>
<br>
_______________________________________________<br>
Piglit mailing list<br>
<a href="mailto:Piglit@lists.freedesktop.org" target="_blank">Piglit@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/piglit" target="_blank">http://lists.freedesktop.org/mailman/listinfo/piglit</a><br>
</font></span></blockquote></div><br></div></div>