static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
                                        int w, int h)
{
    bool be = vs->client_be;
    size_t bytes;
    int zywrle_level;

    if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
        if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
            || vs->tight->quality == 9) {
            zywrle_level = 0;
            vs->zrle->type = VNC_ENCODING_ZRLE;
        } else if (vs->tight->quality < 3) {
            zywrle_level = 3;
        } else if (vs->tight->quality < 6) {
            zywrle_level = 2;
        } else {
            zywrle_level = 1;
        }
    } else {
        zywrle_level = 0;
    }

    vnc_zrle_start(vs);

    switch (vs->client_pf.bytes_per_pixel) {
    case 1:
        zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
        break;

    case 2:
        if (vs->client_pf.gmax > 0x1F) {
            if (be) {
                zrle_encode_16be(vs, x, y, w, h, zywrle_level);
            } else {
                zrle_encode_16le(vs, x, y, w, h, zywrle_level);
            }
        } else {
            if (be) {
                zrle_encode_15be(vs, x, y, w, h, zywrle_level);
            } else {
                zrle_encode_15le(vs, x, y, w, h, zywrle_level);
            }
        }
        break;

    case 4:
    {
        bool fits_in_ls3bytes;
        bool fits_in_ms3bytes;

        fits_in_ls3bytes =
            ((vs->client_pf.rmax << vs->client_pf.rshift) < (1 << 24) &&
             (vs->client_pf.gmax << vs->client_pf.gshift) < (1 << 24) &&
             (vs->client_pf.bmax << vs->client_pf.bshift) < (1 << 24));

        fits_in_ms3bytes = (vs->client_pf.rshift > 7 &&
                            vs->client_pf.gshift > 7 &&
                            vs->client_pf.bshift > 7);

        if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
            if (be) {
                zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
            } else {
                zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
          }
        } else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
            if (be) {
                zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
            } else {
                zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
            }
        } else {
            if (be) {
                zrle_encode_32be(vs, x, y, w, h, zywrle_level);
            } else {
                zrle_encode_32le(vs, x, y, w, h, zywrle_level);
            }
        }
    }
    break;
    }

    vnc_zrle_stop(vs);
    bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
    vnc_write_u32(vs, bytes);
    vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
    return 1;
}