For vertices/patches with a shader and no texCoords, use positions

This was another surprising (to me) inconsistency. Just because these
geometric primitives allow for explicit local coords, doesn't mean we
should require them (vs. all others that implicitly sample using local
position).

Change-Id: If3e7f6077bd15891b06cd2ffc969f1a649305d42
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290130
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-05-15 13:04:48 -04:00 committed by Skia Commit-Bot
parent 1040e38363
commit 8219e91468
5 changed files with 52 additions and 24 deletions

View File

@ -9,6 +9,11 @@ Milestone 85
* <insert new release notes here>
* SkCanvas::drawVertices and drawPatch now support mapping an SkShader without explicit
texture coordinates. If they're not supplied, the local positions (vertex position or
patch cubic positions) will be directly used to sample the SkShader.
https://review.skia.org/290130
* * *
Milestone 84

View File

@ -2164,8 +2164,11 @@ public:
}
/** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
If vertices texs and vertices colors are defined in vertices, and SkPaint paint
contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
If paint contains an SkShader and vertices does not contain texCoords, the shader
is mapped using the vertices' positions.
If vertices colors are defined in vertices, and SkPaint paint contains SkShader,
SkBlendMode mode combines vertices colors with SkShader.
@param vertices triangle mesh to draw
@param mode combines vertices colors with SkShader, if both are present
@ -2183,8 +2186,11 @@ public:
}
/** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
If vertices texs and vertices colors are defined in vertices, and SkPaint paint
contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
If paint contains an SkShader and vertices does not contain texCoords, the shader
is mapped using the vertices' positions.
If vertices colors are defined in vertices, and SkPaint paint contains SkShader,
SkBlendMode mode combines vertices colors with SkShader.
@param vertices triangle mesh to draw
@param mode combines vertices colors with SkShader, if both are present
@ -2217,7 +2223,8 @@ public:
bottom-right, bottom-left order.
If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
corners in top-left, top-right, bottom-right, bottom-left order.
corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is
nullptr, SkShader is mapped using positions (derived from cubics).
@param cubics SkPath cubic array, sharing common points
@param colors color array, one for each corner
@ -2245,7 +2252,8 @@ public:
bottom-right, bottom-left order.
If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
corners in top-left, top-right, bottom-right, bottom-left order.
corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is
nullptr, SkShader is mapped using positions (derived from cubics).
@param cubics SkPath cubic array, sharing common points
@param colors color array, one for each corner

View File

@ -1967,6 +1967,17 @@ void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const
}
}
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
// Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
if (paint.getShader() &&
!(vertices->priv().hasTexCoords() || vertices->priv().hasCustomData())) {
SkPaint noShaderPaint(paint);
noShaderPaint.setShader(nullptr);
this->onDrawVerticesObject(vertices, mode, noShaderPaint);
return;
}
#endif
this->onDrawVerticesObject(vertices, mode, paint);
}

View File

@ -268,11 +268,13 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode,
const uint16_t* indices = info.indices();
const SkColor* colors = info.colors();
// make textures and shader mutually consistent
// No need for texCoords without shader. If shader is present without explicit texCoords,
// use positions instead.
SkShader* shader = paint.getShader();
if (!(shader && textures)) {
shader = nullptr;
if (!shader) {
textures = nullptr;
} else if (!textures) {
textures = positions;
}
// We can simplify things for certain blendmodes. This is for speed, and SkComposeShader
@ -351,6 +353,14 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode,
// all opaque (and the blendmode will keep them that way
}
// Positions as texCoords? The local matrix is always identity, so update once
if (textures == positions) {
SkMatrix localM;
if (!updater->update(ctm, &localM)) {
return;
}
}
auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, outerAlloc,
fRC->clipShader());
while (vertProc(&state)) {
@ -360,9 +370,9 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode,
}
SkMatrix localM;
if (texture_to_matrix(state, positions, textures, &localM) &&
updater->update(ctm, &localM))
{
if ((textures == positions) ||
(texture_to_matrix(state, positions, textures, &localM) &&
updater->update(ctm, &localM))) {
fill_triangle(state, blitter, *fRC, dev2, dev3);
}
}
@ -378,7 +388,7 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode,
const SkMatrixProvider* matrixProvider = fMatrixProvider;
SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
if (textures) {
if (textures && (textures != positions)) {
SkMatrix localM;
if (!texture_to_matrix(state, positions, textures, &localM)) {
continue;

View File

@ -940,12 +940,11 @@ static bool init_vertices_paint(GrContext* context,
const SkPaint& skPaint,
const SkMatrixProvider& matrixProvider,
SkBlendMode bmode,
bool hasTexs,
bool hasColors,
GrPaint* grPaint) {
if (hasTexs && skPaint.getShader()) {
if (skPaint.getShader()) {
if (hasColors) {
// When there are texs and colors the shader and colors are combined using bmode.
// When there are colors and a shader, the shader and colors are combined using bmode.
return SkPaintToGrPaintWithXfermode(context, colorInfo, skPaint, matrixProvider, bmode,
grPaint);
} else {
@ -954,12 +953,11 @@ static bool init_vertices_paint(GrContext* context,
}
} else {
if (hasColors) {
// We have colors, but either have no shader or no texture coords (which implies that
// we should ignore the shader).
// We have colors, but no shader.
return SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, matrixProvider,
grPaint);
} else {
// No colors and no shaders. Just draw with the paint color.
// No colors and no shader. Just draw with the paint color.
return SkPaintToGrPaintNoShader(context, colorInfo, skPaint, matrixProvider, grPaint);
}
}
@ -975,13 +973,9 @@ void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, con
const SkRuntimeEffect* effect =
paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
// Pretend that we have tex coords when using custom per-vertex data. The shader is going to
// use those (rather than local coords), but our paint conversion remains the same.
GrPaint grPaint;
bool hasColors = info.hasColors();
bool hasTexs = info.hasTexCoords() || info.hasCustomData();
if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorInfo(), paint,
this->asMatrixProvider(), mode, hasTexs, hasColors, &grPaint)) {
this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) {
return;
}
fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->asMatrixProvider(),