Changeset 1092


Ignore:
Timestamp:
Nov 28, 2011, 2:58:55 AM (12 years ago)
Author:
sam
Message:

tutorial: work around i915 driver limitations in the Mandelbrot viewer shader.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/test/tutorial/tut03.cpp

    r1090 r1092  
    5757        m_size.x = (m_size.x + 15) & ~15;
    5858        m_size.y = (m_size.y + 15) & ~15;
    59         m_texel_settings = vec4(vec2(1.0, 1.0) / (vec2)m_size,
    60                                 vec2(0.5, 0.5) * (vec2)m_size);
     59        m_texel_settings = vec4(1.0, 1.0, 2.0, 2.0) / (vec4)m_size.xyxy();
     60        m_screen_settings = vec4(1.0, 1.0, 0.5, 0.5) * (vec4)m_size.xyxy();
    6161
    6262        /* Window size decides the world aspect ratio. For instance, 640×480
     
    7979        m_tmppixels = new u8vec4[m_size.x / 2 * m_size.y / 2];
    8080        m_frame = -1;
     81        m_slices = 4;
    8182        for (int i = 0; i < 4; i++)
    8283        {
     
    9798        m_radius = 5.0;
    9899        m_ready = false;
     100        m_drag = false;
    99101
    100102        m_palette = new u8vec4[(MAX_ITERATIONS + 1) * PALETTE_STEP];
     
    158160    }
    159161
    160     inline f64cmplx TexelToWorldOffset(ivec2 texel)
     162    inline f64cmplx TexelToWorldOffset(vec2 texel)
    161163    {
    162164        double dx = (0.5 + texel.x - m_size.x / 2) * m_texel2world.x;
     
    165167    }
    166168
    167     inline f64cmplx ScreenToWorldOffset(ivec2 pixel)
     169    inline f64cmplx ScreenToWorldOffset(vec2 pixel)
    168170    {
    169171        /* No 0.5 offset here, because we want to be able to position the
     
    187189        if (buttons[1])
    188190        {
    189             if (clicked[1])
     191            if (!m_drag)
     192            {
    190193                m_oldmouse = mousepos;
     194                m_drag = true;
     195            }
    191196            m_translate = ScreenToWorldOffset(m_oldmouse)
    192197                        - ScreenToWorldOffset(mousepos);
     198            /* XXX: the purpose of this hack is to avoid translating by
     199             * an exact number of pixels. If this were to happen, the step()
     200             * optimisation for i915 cards in our shader would behave
     201             * incorrectly because a quarter of the pixels in the image
     202             * would have tie rankings in the distance calculation. */
     203            m_translate *= 1023.0 / 1024.0;
    193204            m_oldmouse = mousepos;
    194205        }
    195         else if (m_translate != 0.0)
    196         {
    197             m_translate *= pow(2.0, -deltams * 0.005);
    198             if (m_translate.norm() / m_radius < 1e-4)
    199                 m_translate = 0.0;
     206        else
     207        {
     208            m_drag = false;
     209            if (m_translate != 0.0)
     210            {
     211                m_translate *= pow(2.0, -deltams * 0.005);
     212                if (m_translate.norm() / m_radius < 1e-4)
     213                    m_translate = 0.0;
     214            }
    200215        }
    201216
     
    210225        {
    211226            m_zoom_speed *= pow(2.0, -deltams * 0.005);
    212             if (abs(m_zoom_speed) < 1e-5)
     227            if (abs(m_zoom_speed) < 1e-5 || m_drag)
    213228                m_zoom_speed = 0.0;
    214229        }
     
    287302#endif
    288303
    289         u8vec4 *m_pixelstart = m_pixels + m_size.x * m_size.y / 4 * m_frame;
    290 
    291304        if (m_dirty[m_frame])
    292305        {
    293             double const maxsqlen = 1024;
    294             double const k1 = 1.0 / (1 << 10) / log2(maxsqlen);
    295 
    296306            m_dirty[m_frame]--;
    297307
    298             for (int j = ((m_frame + 1) % 4) / 2; j < m_size.y; j += 2)
    299             for (int i = m_frame % 2; i < m_size.x; i += 2)
    300             {
    301 
    302                 f64cmplx z0 = m_center + TexelToWorldOffset(ivec2(i, j));
    303                 f64cmplx r0 = z0;
    304                 //f64cmplx r0(0.28693186889504513, 0.014286693904085048);
    305                 //f64cmplx r0(0.001643721971153, 0.822467633298876);
    306                 //f64cmplx r0(-1.207205434596, 0.315432814901);
    307                 //f64cmplx r0(-0.79192956889854, -0.14632423080102);
    308                 //f64cmplx r0(0.3245046418497685, 0.04855101129280834);
    309                 f64cmplx z;
    310                 int iter = MAX_ITERATIONS;
    311                 for (z = z0; iter && z.sqlen() < maxsqlen; z = z * z + r0)
    312                     --iter;
    313 
    314                 if (iter)
    315                 {
    316                     double f = iter;
    317                     double n = z.sqlen();
    318                     if (n > maxsqlen * maxsqlen)
    319                         n = maxsqlen * maxsqlen;
    320 
    321                     /* Approximate log(sqrt(n))/log(sqrt(maxsqlen)) */
    322                     union { double n; uint64_t x; } u = { n };
    323                     double k = (u.x >> 42) - (((1 << 10) - 1) << 10);
    324                     k *= k1;
    325 
    326                     /* Approximate log2(k) in [1,2]. */
    327                     f += (- 0.344847817623168308695977510213252644185 * k
    328                           + 2.024664188044341212602376988171727038739) * k
    329                           - 1.674876738008591047163498125918330313237;
    330 
    331                     *m_pixelstart++ = m_palette[(int)(f * PALETTE_STEP)];
    332                 }
    333                 else
    334                 {
    335                     *m_pixelstart++ = u8vec4(0, 0, 0, 255);
    336                 }
     308            /* FIXME: this is the ugliest, most pathetic excuse for a
     309             * threading system that I have seen in a while. */
     310            DoWorkHelper helpers[m_slices];
     311            for (int slice = 0; slice < m_slices; slice++)
     312            {
     313                helpers[slice].fractal = this;
     314                helpers[slice].slice = slice;
     315                helpers[slice].thread = new Thread(DoWorkHelper::Help,
     316                                                   &helpers[slice]);
     317            }
     318            for (int slice = 0; slice < m_slices; slice++)
     319            {
     320                delete helpers[slice].thread;
     321            }
     322        }
     323    }
     324
     325    struct DoWorkHelper
     326    {
     327        Fractal *fractal;
     328        Thread *thread;
     329        int slice;
     330
     331        static void *Help(void *data)
     332        {
     333            DoWorkHelper *helper = (DoWorkHelper *)data;
     334            helper->fractal->DoWork(helper->slice);
     335            return NULL;
     336        }
     337    };
     338
     339    void DoWork(int slice)
     340    {
     341        double const maxsqlen = 1024;
     342        double const k1 = 1.0 / (1 << 10) / log2(maxsqlen);
     343
     344        int jmin = m_size.y * slice / m_slices;
     345        int jmax = m_size.y * (slice + 1) / m_slices;
     346        u8vec4 *m_pixelstart = m_pixels
     347                             + m_size.x * (m_size.y / 4 * m_frame + jmin / 4);
     348
     349        for (int j = ((m_frame + 1) % 4) / 2 + jmin; j < jmax; j += 2)
     350        for (int i = m_frame % 2; i < m_size.x; i += 2)
     351        {
     352            f64cmplx z0 = m_center + TexelToWorldOffset(ivec2(i, j));
     353            f64cmplx r0 = z0;
     354            //f64cmplx r0(0.28693186889504513, 0.014286693904085048);
     355            //f64cmplx r0(0.001643721971153, 0.822467633298876);
     356            //f64cmplx r0(-1.207205434596, 0.315432814901);
     357            //f64cmplx r0(-0.79192956889854, -0.14632423080102);
     358            //f64cmplx r0(0.3245046418497685, 0.04855101129280834);
     359            f64cmplx z;
     360            int iter = MAX_ITERATIONS;
     361            for (z = z0; iter && z.sqlen() < maxsqlen; z = z * z + r0)
     362                --iter;
     363
     364            if (iter)
     365            {
     366                double f = iter;
     367                double n = z.sqlen();
     368                if (n > maxsqlen * maxsqlen)
     369                    n = maxsqlen * maxsqlen;
     370
     371                /* Approximate log(sqrt(n))/log(sqrt(maxsqlen)) */
     372                union { double n; uint64_t x; } u = { n };
     373                double k = (u.x >> 42) - (((1 << 10) - 1) << 10);
     374                k *= k1;
     375
     376                /* Approximate log2(k) in [1,2]. */
     377                f += (- 0.344847817623168308695977510213252644185 * k
     378                      + 2.024664188044341212602376988171727038739) * k
     379                      - 1.674876738008591047163498125918330313237;
     380
     381                *m_pixelstart++ = m_palette[(int)(f * PALETTE_STEP)];
     382            }
     383            else
     384            {
     385                *m_pixelstart++ = u8vec4(0, 0, 0, 255);
    337386            }
    338387        }
     
    391440                "uniform mat4 u_ZoomSettings;"
    392441                "uniform vec4 u_TexelSize;"
     442                "uniform vec4 u_ScreenSize;"
    393443                ""
    394444                "attribute vec2 a_TexCoord;"
     
    419469                "                       u_ZoomSettings[2][1],"
    420470                "                       u_ZoomSettings[3][1]);"
    421                      /* Pass all this to the fragment shader */
    422471                "    v_CenterX = zoomscale * a_TexCoord.x + zoomtx"
    423472                "              + offsets.xyxy * u_TexelSize.x;"
     
    428477                      * this value. We add or remove a slight offset to avoid
    429478                      * rounding issues at the image's edges. */
    430                 "    v_IndexX = v_CenterX * u_TexelSize.z - offsets.zwzw;"
    431                 "    v_IndexY = v_CenterY * u_TexelSize.w - offsets.zwwz;"
     479                "    v_IndexX = v_CenterX * u_ScreenSize.z - (offsets.zwzw + vec4(0.001, 0.002, 0.003, 0.004));"
     480                "    v_IndexY = v_CenterY * u_ScreenSize.w - (offsets.zwwz + vec4(0.0015, 0.0025, 0.0035, 0.0045));"
    432481                "}",
    433482
     
    445494                "void main(void)"
    446495                "{"
     496                "    vec4 v05 = vec4(0.5, 0.5, 0.5, 0.5);"
     497                "    vec4 rx, ry, t0, dx, dy, dd;"
    447498                     /* Get a pixel coordinate from each slice into rx & ry */
    448                 "    vec4 rx = u_TexelSize.x * (1.0 + 2.0 * floor(v_IndexX));"
    449                 "    vec4 ry = u_TexelSize.y * (1.0 + 2.0 * floor(v_IndexY));"
    450                      /* Compute distance to expected pixel in dd */
    451                 "    vec4 v05 = vec4(0.5, 0.5, 0.5, 0.5);"
    452                 "    vec4 t0 = step(abs(rx - v05), v05)"
    453                 "            * step(abs(ry - v05), v05);"
    454                 "    vec4 dx = rx - v_CenterX;"
    455                 "    vec4 dy = ry - v_CenterY;"
     499                "    rx = u_TexelSize.x + u_TexelSize.z * floor(v_IndexX);"
     500                "    ry = u_TexelSize.y + u_TexelSize.w * floor(v_IndexY);"
     501                     /* Compute inverse distance to expected pixel in dd,
     502                      * and put zero if we fall outside the texture. */
     503                "    t0 = step(abs(rx - v05), v05) * step(abs(ry - v05), v05);"
     504                "    dx = rx - v_CenterX;"
     505                "    dy = ry - v_CenterY;"
    456506                //"    vec4 dd = t0 * (abs(dx) + abs(dy));"
    457507                //"    vec4 dd = t0 / (0.001 + sqrt((dx * dx) + (dy * dy)));"
    458                 "    vec4 dd = t0 / (0.000001 + (dx * dx) + (dy * dy));"
     508                "    dd = t0 / (0.000001 + (dx * dx) + (dy * dy));"
    459509                     /* Modify Y coordinate to select proper quarter. */
    460510                "    ry = ry * 0.25 + vec4(0.0, 0.25, 0.5, 0.75);"
    461511                ""
    462512#if 1
    463                      /* Put min(.x,.y) in .x and min(.z,.w) in .z */
    464                 "    vec4 t1 = step(dd, dd.yyww);"
    465                 "    rx = mix(rx, rx.yyww, t1);"
    466                 "    ry = mix(ry, ry.yyww, t1);"
    467                 "    dd = mix(dd, dd.yyww, t1);"
    468                      /* Put min(x,z) in x */
    469                 "    vec4 t2 = step(dd, dd.zzzz);"
    470                 "    rx = mix(rx, rx.zzzz, t2);"
    471                 "    ry = mix(ry, ry.zzzz, t2);"
     513                "\n#if 0\n" /* XXX: disabled until we can autodetect i915 */
     514                     /* t1.x <-- dd.x > dd.y */
     515                     /* t1.y <-- dd.z > dd.w */
     516                "    vec2 t1 = step(dd.xz, dd.yw);"
     517                     /* ret.x <-- max(rx.x, rx.y) wrt. t1.x */
     518                     /* ret.y <-- max(rx.z, rx.w) wrt. t1.y */
     519                     /* ret.z <-- max(ry.x, ry.y) wrt. t1.x */
     520                     /* ret.w <-- max(ry.z, ry.w) wrt. t1.y */
     521                "    vec4 ret = mix(vec4(rx.xz, ry.xz),"
     522                "                   vec4(rx.yw, ry.yw), t1.xyxy);"
     523                     /* dd.x <-- max(dd.x, dd.y) */
     524                     /* dd.z <-- max(dd.z, dd.w) */
     525                "    dd.xy = mix(dd.xz, dd.yw, t1);"
     526                     /* t2 <-- dd.x > dd.z */
     527                "    float t2 = step(dd.x, dd.y);"
     528                     /* ret.x <-- max(ret.x, ret.y); */
     529                     /* ret.y <-- max(ret.z, ret.yw; */
     530                "    ret.xy = mix(ret.xz, ret.yw, t2);"
     531                "\n#else\n"
     532                     /* Fallback for i915 cards -- the trick to reduce the
     533                      * number of operations is to compute both step(a,b)
     534                      * and step(b,a) and hope that their sum is 1. This is
     535                      * almost always the case, and when it isn't we can
     536                      * afford to have a few wrong pixels. However, a real
     537                      * problem is when panning the image, because half the
     538                      * screen is likely to flicker. To avoid this problem,
     539                      * we cheat a little (see m_translate comment above). */
     540                "    vec4 t1 = step(dd.xzyw, dd.ywxz);"
     541                "    vec4 ret = vec4(rx.xz, ry.xz) * t1.zwzw"
     542                "             + vec4(rx.yw, ry.yw) * t1.xyxy;"
     543                "    dd.xy = dd.xz * t1.zw + dd.yw * t1.xy;"
     544                "    vec2 t2 = step(dd.xy, dd.yx);"
     545                "    ret.xy = ret.xz * t2.yy + ret.yw * t2.xx;"
     546                "\n#endif\n"
    472547                     /* Nearest neighbour */
    473                 "    gl_FragColor = texture2D(in_Texture, vec2(rx.x, ry.x));"
     548                "    gl_FragColor = texture2D(in_Texture, ret.xy);"
    474549#else
    475550                     /* Alternate version: some kind of linear interpolation */
     
    546621            m_texattrib = m_shader->GetAttribLocation("a_TexCoord");
    547622            m_texeluni = m_shader->GetUniformLocation("u_TexelSize");
     623            m_screenuni = m_shader->GetUniformLocation("u_ScreenSize");
    548624            m_zoomuni = m_shader->GetUniformLocation("u_ZoomSettings");
    549625            m_ready = true;
     
    592668        m_shader->Bind();
    593669        m_shader->SetUniform(m_texeluni, m_texel_settings);
     670        m_shader->SetUniform(m_screenuni, m_screen_settings);
    594671        m_shader->SetUniform(m_zoomuni, m_zoom_settings);
    595672#if !defined __CELLOS_LV2__ && !defined __ANDROID__
     
    642719    GLuint m_tco;
    643720#endif
    644     int m_vertexattrib, m_texattrib, m_texeluni, m_zoomuni;
    645     int m_frame, m_dirty[4];
    646     bool m_ready;
     721    int m_vertexattrib, m_texattrib, m_texeluni, m_screenuni, m_zoomuni;
     722    int m_frame, m_slices, m_dirty[4];
     723    bool m_ready, m_drag;
    647724
    648725    f64cmplx m_center, m_translate;
    649726    double m_zoom_speed, m_radius;
    650     vec4 m_texel_settings;
     727    vec4 m_texel_settings, m_screen_settings;
    651728    mat4 m_zoom_settings;
    652729    f64cmplx m_deltashift[4];
Note: See TracChangeset for help on using the changeset viewer.