Am 09.01.2016 um 04:09 schrieb Ian Romanick: > On 01/08/2016 05:12 PM, srol...@vmware.com wrote: >> From: Roland Scheidegger <srol...@vmware.com> >> >> The rect halves comparison is in fact not valid in general. The reason is >> that >> the same geometry does not have the same precision even if it it just shifted >> by some fixed amount in one direction. >> As an example, some calculated x value near 7 will be near 263 if drawn with >> a viewport x value of 256. The value near 7 has 5 bits more precision - >> when calculating the fixed-point values for rasterization (with subpixel >> accuracy), the lower value thus may be rounded in a different direction >> than the higher one, even with correct rounding (not even entirely sure what >> "correct" rounding here means, nearest-floor or nearest-even or whatever, the >> problem is independent from that). This can then cause different pixels to be >> covered by the primitive. >> This causes a failure with this test in llvmpipe when the rounding mode is >> changed slightly (from "mostly" nearest-away-from-zero to nearest-even). I >> was >> not able to reproduce this with this test on nvidia or amd hardware, but they >> are definitely affected in theory by the same issue (proven by some quick and >> dirty test). >> So, simply add then subtract some fixed amount to the position values, which >> ensures there should be no differences in the position later even after >> viewport translate (we use window size + 1 here, so the values in range >> -1.0 - +1.0 will all have the same exponent (just above the window size)). >> (We must do that with uniforms otherwise mesa will optimize the add/sub away >> - >> this is definitely unsafe math optimization but may well be allowed.) >> >> This may be a problem with more tests, albeit most tend to use vertex data >> which is already sufficiently aligned (e.g. drawing simple aligned rects). >> --- >> tests/general/quad-invariance.c | 55 >> +++++++++------------- >> .../glsl-1.50/execution/geometry/end-primitive.c | 15 +++++- >> 2 files changed, 36 insertions(+), 34 deletions(-) >> >> diff --git a/tests/general/quad-invariance.c >> b/tests/general/quad-invariance.c >> index b5741d0..fd51dec 100644 >> --- a/tests/general/quad-invariance.c >> +++ b/tests/general/quad-invariance.c >> @@ -38,9 +38,13 @@ >> >> #include "piglit-util-gl.h" >> >> +#define PATTERN_SIZE 256 >> + >> PIGLIT_GL_TEST_CONFIG_BEGIN >> >> config.supports_gl_compat_version = 10; >> + config.window_width = 2*PATTERN_SIZE; >> + config.window_height = PATTERN_SIZE; >> >> config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE; >> >> @@ -49,41 +53,24 @@ PIGLIT_GL_TEST_CONFIG_END >> enum piglit_result >> piglit_display(void) >> { >> + int i; >> GLboolean pass = GL_TRUE; >> - float verts[12][2] = { >> + float verts[3][2] = { >> /* prim 1: left half of screen. */ >> - {-1.0, -1.0}, >> - { 0.0, -1.0}, >> - { 0.0, 1.0}, >> - {-1.0, 1.0}, >> - /* prim 2: right half of screen. */ >> - { 0.0, -1.0}, >> - { 1.0, -1.0}, >> - { 1.0, 1.0}, >> + {-1.0 + 2.0f / PATTERN_SIZE, -1.0}, >> + {-1.0 + 2.0f / PATTERN_SIZE, 1.0}, >> { 0.0, 1.0}, >> - /* prim 3: somewhere off the screen. */ >> - { 2.0, -1.0}, >> - { 3.0, -1.0}, >> - { 3.0, 1.0}, >> - { 2.0, 1.0}, >> }; >> - float colors[12][4] = { >> - {1.0, 0.0, 0.0, 0.0}, >> - {0.0, 1.0, 0.0, 0.0}, >> - {0.0, 0.0, 1.0, 0.0}, >> - {1.0, 1.0, 1.0, 0.0}, >> - >> - {1.0, 0.0, 0.0, 0.0}, >> - {0.0, 1.0, 0.0, 0.0}, >> - {0.0, 0.0, 1.0, 0.0}, >> - {1.0, 1.0, 1.0, 0.0}, >> - >> - {1.0, 0.0, 0.0, 0.0}, >> - {0.0, 1.0, 0.0, 0.0}, >> - {0.0, 0.0, 1.0, 0.0}, >> - {1.0, 1.0, 1.0, 0.0}, >> + float colors[3][4] = { >> + {1.0, 0.0, 0.0, 1.0}, >> + {1.0, 0.0, 0.0, 1.0}, >> + {1.0, 0.0, 0.0, 1.0}, >> + >> }; >> + >> static GLboolean once = GL_TRUE; >> + for (i = 0; i < (1 << 24) && pass; i++) { >> + verts[1][0] += 5.96046447754E-08f * 2.0f; >> >> glClearColor(0.0, 0.0, 0.0, 0.0); >> glClear(GL_COLOR_BUFFER_BIT); >> @@ -94,19 +81,21 @@ piglit_display(void) >> glEnableClientState(GL_VERTEX_ARRAY); >> >> /* left: 1 prim */ >> - glDrawArrays(GL_QUADS, 0, 4); >> + glViewport(0, 0, piglit_width/2, piglit_height); >> + glDrawArrays(GL_TRIANGLES, 0, 3); >> >> + glViewport(piglit_width/2, 0, piglit_width/2, piglit_height); >> /* right: 1 prim */ >> - glDrawArrays(GL_QUADS, 4, 8); >> + glDrawArrays(GL_TRIANGLES, 0, 3); >> >> if (once) { >> printf("Left and right half should match.\n"); >> once = GL_FALSE; >> } >> >> - pass = piglit_probe_rect_halves_equal_rgba(0, 0, piglit_width, >> + pass &= piglit_probe_rect_halves_equal_rgba(0, 0, piglit_width, >> piglit_height); >> - >> + } >> piglit_present_results(); >> >> return pass ? PIGLIT_PASS : PIGLIT_WARN; >> diff --git a/tests/spec/glsl-1.50/execution/geometry/end-primitive.c >> b/tests/spec/glsl-1.50/execution/geometry/end-primitive.c >> index 6df3a89..e251ad0 100644 >> --- a/tests/spec/glsl-1.50/execution/geometry/end-primitive.c >> +++ b/tests/spec/glsl-1.50/execution/geometry/end-primitive.c >> @@ -92,6 +92,8 @@ static const char *spiral_text = >> "#version 150\n" >> "\n" >> "uniform int num_vertices;\n" >> + "uniform float hack1;\n" >> + "uniform float hack2;\n" >> "\n" >> "vec2 spiral(int vertex_id)\n" >> "{\n" >> @@ -105,7 +107,10 @@ static const char *spiral_text = >> " if (vertex_id % 2 == 1) r += 1.0;\n" >> " float max_r = b*sqrt(a*float(num_vertices)) + 1.0;\n" >> " r /= max_r;\n" >> - " return r*vec2(cos(theta), sin(theta));\n" >> + " vec2 tmp = r*vec2(cos(theta), sin(theta));\n" >> + " // ensure reasonably aligned vertices \n" >> + " // note cannot use literals as they'd get optimized away... \n" >> + " return tmp + hack1 - hack2;\n" > > This works only by luck, and it's probably the only use-case I've seen > for the precise keyword. :) If the compiler stack decided to rearrange > this expression as tmp + (hack1 - hack2), you'd be right back where you > started. Without the precise keyword, the GLSL compiler is allowed to > do that. Oh indeed you're quite right, I didn't think of that (albeit the compiler actually combined the first add into a mad together with the preceding mul).
> > I haven't looked at the rest of the shader, so I don't have an alternate > suggestion. Maybe do something like floor(tmp * large_constant) / > large_constant? Yes I was first thinking about mul + int conversion and back before I thought a add is easier, but of course the actual conversion isn't needed and floor should do. Something like 2^10 should probably do (basically still have some minimal subpixel bits for this size of the vp). I suppose maybe (tmp + hack1) * hack2 - hack1 would also do? (with hack2 being uniform 1.0 of course). Albeit technically the compiler could do tmp*hack2 + hack1*hack2 - hack1 again, grmpf. Though I'm not sure why the compiler would do this. Roland > > Also, piglit uses hard tabs for indentation. Right, I'll fix that. > >> "}\n"; >> >> /** >> @@ -303,6 +308,10 @@ draw_ref_pattern() >> glUseProgram(prog_ref); >> glUniform1i(glGetUniformLocation(prog_ref, "num_vertices"), >> num_vertices); >> + glUniform1f(glGetUniformLocation(prog_ref, "hack1"), >> + (float)PATTERN_SIZE * 2.0f + 1.0f); >> + glUniform1f(glGetUniformLocation(prog_ref, "hack2"), >> + (float)PATTERN_SIZE * 2.0f + 1.0f); >> glEnable(GL_PRIMITIVE_RESTART); >> glPrimitiveRestartIndex(0xffffffff); >> >> @@ -342,6 +351,10 @@ draw_test_pattern() >> glUseProgram(prog_test); >> glUniform1i(glGetUniformLocation(prog_test, "num_vertices"), >> num_vertices); >> + glUniform1f(glGetUniformLocation(prog_ref, "hack1"), >> + (float)PATTERN_SIZE * 2.0f + 1.0f); >> + glUniform1f(glGetUniformLocation(prog_ref, "hack2"), >> + (float)PATTERN_SIZE * 2.0f + 1.0f); >> glDrawArrays(GL_POINTS, 0, 3); >> } >> >> > _______________________________________________ Piglit mailing list Piglit@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/piglit