Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  brush_image.glsl   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#define VECS_PER_SPECIFIC_BRUSH 3

#include shared,prim_shared,brush

// Interpolated UV coordinates to sample.
varying highp vec2 v_uv;

#ifdef WR_FEATURE_ALPHA_PASS
flat varying mediump vec4 v_color;
flat varying mediump vec2 v_mask_swizzle;
flat varying mediump vec2 v_tile_repeat_bounds;
#endif

// Normalized bounds of the source image in the texture.
flat varying highp vec4 v_uv_bounds;
// Normalized bounds of the source image in the texture, adjusted to avoid
// sampling artifacts.
flat varying highp vec4 v_uv_sample_bounds;

// Flag to allow perspective interpolation of UV.
// Packed in to vector to work around bug 1630356.
flat varying mediump vec2 v_perspective;

#ifdef WR_VERTEX_SHADER

// Must match the AlphaType enum.
#define BLEND_MODE_ALPHA            0
#define BLEND_MODE_PREMUL_ALPHA     1

struct ImageBrushData {
    vec4 color;
    vec4 background_color;
    vec2 stretch_size;
};

ImageBrushData fetch_image_data(int address) {
    vec4[3] raw_data = fetch_from_gpu_cache_3(address);
    ImageBrushData data = ImageBrushData(
        raw_data[0],
        raw_data[1],
        raw_data[2].xy
    );
    return data;
}

vec2 modf2(vec2 x, vec2 y) {
    return x - y * floor(x/y);
}

void brush_vs(
    VertexInfo vi,
    int prim_address,
    RectWithEndpoint prim_rect,
    RectWithEndpoint segment_rect,
    ivec4 prim_user_data,
    int specific_resource_address,
    mat4 transform,
    PictureTask pic_task,
    int brush_flags,
    vec4 segment_data
) {
    ImageBrushData image_data = fetch_image_data(prim_address);

    // If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
    // non-normalized texture coordinates.
#ifdef WR_FEATURE_TEXTURE_RECT
    vec2 texture_size = vec2(1, 1);
#else
    vec2 texture_size = vec2(TEX_SIZE(sColor0));
#endif

    ImageSource res = fetch_image_source(specific_resource_address);
    vec2 uv0 = res.uv_rect.p0;
    vec2 uv1 = res.uv_rect.p1;

    RectWithEndpoint local_rect = prim_rect;
    vec2 stretch_size = image_data.stretch_size;
    if (stretch_size.x < 0.0) {
        stretch_size = rect_size(local_rect);
    }

    // If this segment should interpolate relative to the
    // segment, modify the parameters for that.
    if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
        local_rect = segment_rect;
        stretch_size = rect_size(local_rect);

        if ((brush_flags & BRUSH_FLAG_TEXEL_RECT) != 0) {
            // If the extra data is a texel rect, modify the UVs.
            vec2 uv_size = res.uv_rect.p1 - res.uv_rect.p0;
            uv0 = res.uv_rect.p0 + segment_data.xy * uv_size;
            uv1 = res.uv_rect.p0 + segment_data.zw * uv_size;
        }

        #ifdef WR_FEATURE_REPETITION
            // TODO(bug 1609893): Move this logic to the CPU as well as other sources of
            // branchiness in this shader.
            if ((brush_flags & BRUSH_FLAG_TEXEL_RECT) != 0) {
                // Value of the stretch size with repetition. We have to compute it for
                // both axis even if we only repeat on one axis because the value for
                // each axis depends on what the repeated value would have been for the
                // other axis.
                vec2 repeated_stretch_size = stretch_size;
                // Size of the uv rect of the segment we are considering when computing
                // the repetitions. For the fill area it is a tad more complicated as we
                // have to use the uv size of the top-middle segment to drive horizontal
                // repetitions, and the size of the left-middle segment to drive vertical
                // repetitions. So we track the reference sizes for both axis separately
                // even though in the common case (the border segments) they are the same.
                vec2 horizontal_uv_size = uv1 - uv0;
                vec2 vertical_uv_size = uv1 - uv0;
                // We use top and left sizes by default and fall back to bottom and right
                // when a size is empty.
                if ((brush_flags & BRUSH_FLAG_SEGMENT_NINEPATCH_MIDDLE) != 0) {
                    repeated_stretch_size = segment_rect.p0 - prim_rect.p0;

                    float epsilon = 0.001;

                    // Adjust the the referecne uv size to compute vertical repetitions for
                    // the fill area.
                    vertical_uv_size.x = uv0.x - res.uv_rect.p0.x;
                    if (vertical_uv_size.x < epsilon || repeated_stretch_size.x < epsilon) {
                        vertical_uv_size.x = res.uv_rect.p1.x - uv1.x;
                        repeated_stretch_size.x = prim_rect.p1.x - segment_rect.p1.x;
                    }

                    // Adjust the the referecne uv size to compute horizontal repetitions
                    // for the fill area.
                    horizontal_uv_size.y = uv0.y - res.uv_rect.p0.y;
                    if (horizontal_uv_size.y < epsilon || repeated_stretch_size.y < epsilon) {
                        horizontal_uv_size.y = res.uv_rect.p1.y - uv1.y;
                        repeated_stretch_size.y = prim_rect.p1.y - segment_rect.p1.y;
                    }
                }

                if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X) != 0) {
                    float uv_ratio = horizontal_uv_size.x / horizontal_uv_size.y;
                    stretch_size.x = repeated_stretch_size.y * uv_ratio;
                }
                if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y) != 0) {
                    float uv_ratio = vertical_uv_size.y / vertical_uv_size.x;
                    stretch_size.y = repeated_stretch_size.x * uv_ratio;
                }

            } else {
                if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X) != 0) {
                    stretch_size.x = segment_data.z - segment_data.x;
                }
                if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y) != 0) {
                    stretch_size.y = segment_data.w - segment_data.y;
                }
            }
            if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X_ROUND) != 0) {
                float segment_rect_width = segment_rect.p1.x - segment_rect.p0.x;
                float nx = max(1.0, round(segment_rect_width / stretch_size.x));
                stretch_size.x = segment_rect_width / nx;
            }
            if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y_ROUND) != 0) {
                float segment_rect_height = segment_rect.p1.y - segment_rect.p0.y;
                float ny = max(1.0, round(segment_rect_height / stretch_size.y));
                stretch_size.y = segment_rect_height / ny;
            }
        #endif
    }

    float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
    v_perspective.x = perspective_interpolate;

    // We deliberately only support the normalized UVs flag when *not* using
    // repetition, as the presence of this code resulted in a miscompilation
    // in the repetition variant on some devices, causing incorrect rendering
    // even when the flag is unset. Perhaps due to the excessive number of
    // branches in the repetition code, and this one broke the camel's back?
    // See bug 1932416 and bug 1929799.
#ifndef WR_FEATURE_REPETITION
    vec2 uv_scale = mix(vec2(1.0), texture_size,
                        bvec2((brush_flags & BRUSH_FLAG_NORMALIZED_UVS) != 0));
    uv0 *= uv_scale;
    uv1 *= uv_scale;
#endif

    // Handle case where the UV coords are inverted (e.g. from an
    // external image).
    vec2 min_uv = min(uv0, uv1);
    vec2 max_uv = max(uv0, uv1);

    v_uv_sample_bounds = vec4(
        min_uv + vec2(0.5),
        max_uv - vec2(0.5)
    ) / texture_size.xyxy;

    vec2 f = (vi.local_pos - local_rect.p0) / rect_size(local_rect);

#ifdef WR_FEATURE_ALPHA_PASS
    int color_mode = prim_user_data.x & 0xffff;
    int blend_mode = prim_user_data.x >> 16;

#endif

    // Derive the texture coordinates for this image, based on
    // whether the source image is a local-space or screen-space
    // image.
    int raster_space = prim_user_data.y;
    if (raster_space == RASTER_SCREEN) {
        // Since the screen space UVs specify an arbitrary quad, do
        // a bilinear interpolation to get the correct UV for this
        // local position.
        f = get_image_quad_uv(specific_resource_address, f);
    }

    // Offset and scale v_uv here to avoid doing it in the fragment shader.
    vec2 repeat = rect_size(local_rect) / stretch_size;
    v_uv = mix(uv0, uv1, f) - min_uv;
    v_uv *= repeat.xy;

    vec2 normalized_offset = vec2(0.0);
#ifdef WR_FEATURE_REPETITION
    // In the case of border-image-repeat: repeat, we must apply an offset so that
    // the first tile is centered.
    //
    // This is derived from:
    //   uv_size = max_uv - min_uv
    //   repeat = local_rect.size / stetch_size
    //   layout_offset = local_rect.size / 2 - strecth_size / 2
    //   texel_offset = layout_offset * uv_size / stretch_size
    //   texel_offset = uv_size / 2 * (local_rect.size / stretch_size - stretch_size / stretch_size)
    //   texel_offset = uv_size / 2 * (repeat - 1)
    //
    // The offset is then adjusted so that it loops in the [0, uv_size] range.
    // In principle this is simply a modulo:
    //
    //   adjusted_offset = fact((repeat - 1)/2) * uv_size
    //
    // However we don't want fract's behavior with negative numbers which happens when the pattern
    // is larger than the local rect (repeat is between 0 and 1), so we shift the content by 1 to
    // remain positive.
    //
    //   adjusted_offset = fract(repeat/2 - 1/2 + 1) * uv_size
    //
    // `uv - offset` will go through another modulo in the fragment shader for which we again don't
    // want the behavior for nagative numbers. We rearrange this here in the form
    // `uv + (uv_size - offset)` to prevent that.
    //
    //   adjusted_offset = (1 - fract(repeat/2 - 1/2 + 1)) * uv_size
    //
    // We then separate the normalized part of the offset which we also need elsewhere.
    bvec2 centered = bvec2(brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X_CENTERED,
                           brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y_CENTERED);
    // Use mix() rather than if statements due to a miscompilation on Adreno 3xx. See bug 1853573.
    normalized_offset = mix(vec2(0.0), 1.0 - fract(repeat * 0.5 + 0.5), centered);
    v_uv += normalized_offset * (max_uv - min_uv);
#endif
    v_uv /= texture_size;
    if (perspective_interpolate == 0.0) {
        v_uv *= vi.world_pos.w;
    }

#ifdef WR_FEATURE_TEXTURE_RECT
    v_uv_bounds = vec4(0.0, 0.0, vec2(textureSize(sColor0)));
#else
    v_uv_bounds = vec4(min_uv, max_uv) / texture_size.xyxy;
#endif

#ifdef WR_FEATURE_REPETITION
    // Normalize UV to 0..1 scale only if using repetition. Otherwise, leave
    // UVs unnormalized since we won't compute a modulus without repetition
    // enabled.
    v_uv /= (v_uv_bounds.zw - v_uv_bounds.xy);
#endif

#ifdef WR_FEATURE_ALPHA_PASS
    v_tile_repeat_bounds = repeat.xy + normalized_offset;

    float opacity = float(prim_user_data.z) / 65535.0;
    switch (blend_mode) {
        case BLEND_MODE_ALPHA:
            image_data.color.a *= opacity;
            break;
        case BLEND_MODE_PREMUL_ALPHA:
        default:
            image_data.color *= opacity;
            break;
    }

    switch (color_mode) {
        case COLOR_MODE_ALPHA:
        case COLOR_MODE_BITMAP_SHADOW:
            #ifdef SWGL_BLEND
                swgl_blendDropShadow(image_data.color);
                v_mask_swizzle = vec2(1.0, 0.0);
                v_color = vec4(1.0);
            #else
                v_mask_swizzle = vec2(0.0, 1.0);
                v_color = image_data.color;
            #endif
            break;
        case COLOR_MODE_IMAGE:
            v_mask_swizzle = vec2(1.0, 0.0);
            v_color = image_data.color;
            break;
        case COLOR_MODE_COLOR_BITMAP:
            v_mask_swizzle = vec2(1.0, 0.0);
            v_color = vec4(image_data.color.a);
            break;
        case COLOR_MODE_SUBPX_DUAL_SOURCE:
            v_mask_swizzle = vec2(image_data.color.a, 0.0);
            v_color = image_data.color;
            break;
        case COLOR_MODE_MULTIPLY_DUAL_SOURCE:
            v_mask_swizzle = vec2(-image_data.color.a, image_data.color.a);
            v_color = image_data.color;
            break;
        default:
            v_mask_swizzle = vec2(0.0);
            v_color = vec4(1.0);
    }
#endif
}
#endif

#ifdef WR_FRAGMENT_SHADER

vec2 compute_repeated_uvs(float perspective_divisor) {
#ifdef WR_FEATURE_REPETITION
    vec2 uv_size = v_uv_bounds.zw - v_uv_bounds.xy;

    #ifdef WR_FEATURE_ALPHA_PASS
    vec2 local_uv = v_uv * perspective_divisor;
    // This prevents the uv on the top and left parts of the primitive that was inflated
    // for anti-aliasing purposes from going beyound the range covered by the regular
    // (non-inflated) primitive.
    local_uv = max(local_uv, vec2(0.0));

    // Handle horizontal and vertical repetitions.
    vec2 repeated_uv = fract(local_uv) * uv_size + v_uv_bounds.xy;

    // This takes care of the bottom and right inflated parts.
    // We do it after the modulo because the latter wraps around the values exactly on
    // the right and bottom edges, which we do not want.
    if (local_uv.x >= v_tile_repeat_bounds.x) {
        repeated_uv.x = v_uv_bounds.z;
    }
    if (local_uv.y >= v_tile_repeat_bounds.y) {
        repeated_uv.y = v_uv_bounds.w;
    }
    #else
    vec2 repeated_uv = fract(v_uv * perspective_divisor) * uv_size + v_uv_bounds.xy;
    #endif

    return repeated_uv;
#else
    return v_uv * perspective_divisor + v_uv_bounds.xy;
#endif
}

Fragment brush_fs() {
    float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_perspective.x);
    vec2 repeated_uv = compute_repeated_uvs(perspective_divisor);

    // Clamp the uvs to avoid sampling artifacts.
    vec2 uv = clamp(repeated_uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw);

    vec4 texel = TEX_SAMPLE(sColor0, uv);

    Fragment frag;

#ifdef WR_FEATURE_ALPHA_PASS
    #ifdef WR_FEATURE_ANTIALIASING
        float alpha = antialias_brush();
    #else
        float alpha = 1.0;
    #endif
    #ifndef WR_FEATURE_DUAL_SOURCE_BLENDING
        texel.rgb = texel.rgb * v_mask_swizzle.x + texel.aaa * v_mask_swizzle.y;
    #endif

    vec4 alpha_mask = texel * alpha;
    frag.color = v_color * alpha_mask;

    #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
        frag.blend = alpha_mask * v_mask_swizzle.x + alpha_mask.aaaa * v_mask_swizzle.y;
    #endif
#else
    frag.color = texel;
#endif

    return frag;
}

#if defined(SWGL_DRAW_SPAN) && (!defined(WR_FEATURE_ALPHA_PASS) || !defined(WR_FEATURE_DUAL_SOURCE_BLENDING))
void swgl_drawSpanRGBA8() {
    if (!swgl_isTextureRGBA8(sColor0)) {
        return;
    }

    #ifdef WR_FEATURE_ALPHA_PASS
        if (v_mask_swizzle != vec2(1.0, 0.0)) {
            return;
        }
    #endif

    float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, v_perspective.x);

    #ifdef WR_FEATURE_REPETITION
        // Get the UVs before any repetition, scaling, or offsetting has occurred...
        vec2 uv = v_uv * perspective_divisor;
    #else
        vec2 uv = compute_repeated_uvs(perspective_divisor);
    #endif

    #ifdef WR_FEATURE_ALPHA_PASS
    if (v_color != vec4(1.0)) {
        #ifdef WR_FEATURE_REPETITION
            swgl_commitTextureRepeatColorRGBA8(sColor0, uv, v_tile_repeat_bounds, v_uv_bounds, v_uv_sample_bounds, v_color);
        #else
            swgl_commitTextureColorRGBA8(sColor0, uv, v_uv_sample_bounds, v_color);
        #endif
        return;
    }
    // No color scaling required, so just fall through to a normal textured span...
    #endif

    #ifdef WR_FEATURE_REPETITION
        #ifdef WR_FEATURE_ALPHA_PASS
            swgl_commitTextureRepeatRGBA8(sColor0, uv, v_tile_repeat_bounds, v_uv_bounds, v_uv_sample_bounds);
        #else
            swgl_commitTextureRepeatRGBA8(sColor0, uv, vec2(0.0), v_uv_bounds, v_uv_sample_bounds);
        #endif
    #else
        swgl_commitTextureRGBA8(sColor0, uv, v_uv_sample_bounds);
    #endif
}
#endif

#endif

[ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge