Make GrTextureOp capable of edge antialiasing.

Bug: skia:
Change-Id: I0088bdbb6a76811611fa4628656bf9513c5bf04a
Reviewed-on: https://skia-review.googlesource.com/91105
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-01-11 11:46:21 -05:00 committed by Skia Commit-Bot
parent ac47b88d3c
commit b5ef1f9b13
7 changed files with 301 additions and 107 deletions

View File

@ -16,12 +16,16 @@
class MultitextureImages : public Benchmark {
public:
MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing)
MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing, bool aa)
: fImageSize(imageSize)
, fDstRectSize(dstRectSize)
, fDisableMultitexturing(disableMultitexturing) {
, fDisableMultitexturing(disableMultitexturing)
, fAA(aa) {
fName.appendf("multitexture_images_%dx%d_image_%dx%d_rect", imageSize, imageSize,
dstRectSize, dstRectSize);
if (aa) {
fName.append("_aa");
}
if (disableMultitexturing) {
fName.append("_disable_multitexturing");
}
@ -60,6 +64,7 @@ protected:
SkPaint paint;
paint.setAlpha(0x40);
paint.setFilterQuality(kLow_SkFilterQuality);
paint.setAntiAlias(fAA);
for (int i = 0; i < loops; i++) {
for (int j = 0; j < kNumImages; ++j) {
SkVector translate = this->translation(i * kNumImages + j);
@ -87,8 +92,9 @@ private:
SkVector translation(int i) const {
SkVector offset;
offset.fX = i % kNumColumns * kTranslate;
offset.fY = (i / kNumColumns) % kNumRows * kTranslate;
// Fractional offsets to ensure we can't ignore antialiasing.
offset.fX = i % kNumColumns * kTranslate + 0.1f;
offset.fY = (i / kNumColumns) % kNumRows * kTranslate + 0.1f;
return offset;
}
@ -102,24 +108,32 @@ private:
int fImageSize;
int fDstRectSize;
bool fDisableMultitexturing;
bool fAA;
typedef Benchmark INHERITED;
};
DEF_BENCH(return new MultitextureImages(128, 32, false));
DEF_BENCH(return new MultitextureImages(128, 32, true));
DEF_BENCH(return new MultitextureImages(128, 128, false));
DEF_BENCH(return new MultitextureImages(128, 128, true));
DEF_BENCH(return new MultitextureImages(128, 256, false));
DEF_BENCH(return new MultitextureImages(128, 256, true));
// Non-AA
DEF_BENCH(return new MultitextureImages(128, 32, false, false));
DEF_BENCH(return new MultitextureImages(128, 32, true, false));
DEF_BENCH(return new MultitextureImages(128, 128, false, false));
DEF_BENCH(return new MultitextureImages(128, 128, true, false));
DEF_BENCH(return new MultitextureImages(128, 256, false, false));
DEF_BENCH(return new MultitextureImages(128, 256, true, false));
DEF_BENCH(return new MultitextureImages(512, 32, false));
DEF_BENCH(return new MultitextureImages(512, 32, true));
DEF_BENCH(return new MultitextureImages(512, 128, false));
DEF_BENCH(return new MultitextureImages(512, 128, true));
DEF_BENCH(return new MultitextureImages(512, 256, false));
DEF_BENCH(return new MultitextureImages(512, 256, true));
DEF_BENCH(return new MultitextureImages(512, 512, false));
DEF_BENCH(return new MultitextureImages(512, 512, true));
DEF_BENCH(return new MultitextureImages(512, 32, false, false));
DEF_BENCH(return new MultitextureImages(512, 32, true, false));
DEF_BENCH(return new MultitextureImages(512, 128, false, false));
DEF_BENCH(return new MultitextureImages(512, 128, true, false));
DEF_BENCH(return new MultitextureImages(512, 256, false, false));
DEF_BENCH(return new MultitextureImages(512, 256, true, false));
DEF_BENCH(return new MultitextureImages(512, 512, false, false));
DEF_BENCH(return new MultitextureImages(512, 512, true, false));
// AA
DEF_BENCH(return new MultitextureImages(512, 512, true, true));
DEF_BENCH(return new MultitextureImages(512, 512, false, true));
DEF_BENCH(return new MultitextureImages(128, 32, true, true));
DEF_BENCH(return new MultitextureImages(128, 32, false, true));
#endif

View File

@ -49,7 +49,11 @@ public:
return GrShaderVar(fName, GrVertexAttribTypeToSLType(fType),
GrShaderVar::kIn_TypeModifier);
}
const char* fName;
bool isInitialized() const { return SkToBool(fName); }
Attribute() = default;
Attribute(const char* name, GrVertexAttribType type, int offset, InputRate rate)
: fName(name), fType(type), fOffsetInRecord(offset), fInputRate(rate) {}
const char* fName = nullptr;
GrVertexAttribType fType;
int fOffsetInRecord;
InputRate fInputRate;

View File

@ -766,7 +766,7 @@ static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ct
void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
GrSamplerState::Filter filter, GrColor color,
const SkRect& srcRect, const SkRect& dstRect,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> colorSpaceXform) {
ASSERT_SINGLE_OWNER
@ -785,9 +785,9 @@ void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextur
}
bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace());
this->addDrawOp(clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect,
clippedDstRect, viewMatrix, std::move(colorSpaceXform),
allowSRGB));
this->addDrawOp(
clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, clippedDstRect,
aa, viewMatrix, std::move(colorSpaceXform), allowSRGB));
}
void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,

View File

@ -145,11 +145,10 @@ public:
* Creates an op that draws a subrectangle of a texture. The passed color is modulated by the
* texture's color. 'srcRect' specifies the rectangle of the texture to draw. 'dstRect'
* specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to
* device space. The edges of the rendered rectangle are not antialiased. This asserts that the
* view matrix does not have perspective.
* device space. This asserts that the view matrix does not have perspective.
*/
void drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter,
GrColor, const SkRect& srcRect, const SkRect& dstRect,
GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>);
/**

View File

@ -94,14 +94,13 @@ static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer,
static bool can_use_draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm,
SkCanvas::SrcRectConstraint constraint) {
return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
!paint.getImageFilter() && !paint.isAntiAlias() &&
paint.getFilterQuality() < kMedium_SkFilterQuality &&
!paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality &&
paint.getBlendMode() == SkBlendMode::kSrcOver && !ctm.hasPerspective() &&
SkCanvas::kFast_SrcRectConstraint == constraint);
}
static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src,
const SkRect* dst, sk_sp<GrTextureProxy> proxy,
const SkRect* dst, GrAA aa, sk_sp<GrTextureProxy> proxy,
SkColorSpace* colorSpace, const GrClip& clip,
GrRenderTargetContext* rtc) {
SkASSERT(!(SkToBool(src) && !SkToBool(dst)));
@ -131,7 +130,7 @@ static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const
GrColor color = GrPixelConfigIsAlphaOnly(proxy->config())
? SkColorToPremulGrColor(paint.getColor())
: SkColorAlphaToGrColor(paint.getColor());
rtc->drawTextureAffine(clip, std::move(proxy), filter, color, srcRect, dstRect, ctm,
rtc->drawTextureAffine(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, ctm,
std::move(csxf));
}
@ -143,8 +142,8 @@ void SkGpuDevice::drawPinnedTextureProxy(sk_sp<GrTextureProxy> proxy, uint32_t p
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix, const SkPaint& paint) {
if (can_use_draw_texture_affine(paint, this->ctm(), constraint)) {
draw_texture_affine(paint, viewMatrix, srcRect, dstRect, std::move(proxy), colorSpace,
this->clip(), fRenderTargetContext.get());
draw_texture_affine(paint, viewMatrix, srcRect, dstRect, GrAA(paint.isAntiAlias()),
std::move(proxy), colorSpace, this->clip(), fRenderTargetContext.get());
return;
}
GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID,
@ -166,8 +165,8 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH
if (!proxy) {
return;
}
draw_texture_affine(paint, viewMatrix, srcRect, dstRect, std::move(proxy), cs.get(),
this->clip(), fRenderTargetContext.get());
draw_texture_affine(paint, viewMatrix, srcRect, dstRect, GrAA(paint.isAntiAlias()),
std::move(proxy), cs.get(), this->clip(), fRenderTargetContext.get());
return;
}
this->drawTextureProducer(maker, srcRect, dstRect, constraint, viewMatrix, paint);

View File

@ -20,9 +20,13 @@
#include "GrTextureProxy.h"
#include "SkGr.h"
#include "SkMathPriv.h"
#include "SkPoint.h"
#include "SkPoint3.h"
#include "glsl/GrGLSLColorSpaceXformHelper.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
namespace {
@ -38,12 +42,25 @@ public:
SkPoint fTextureCoords;
GrColor fColor;
};
struct AAVertex {
SkPoint fPosition;
SkPoint fTextureCoords;
SkPoint3 fEdges[4];
GrColor fColor;
};
struct MultiTextureVertex {
SkPoint fPosition;
int fTextureIdx;
SkPoint fTextureCoords;
GrColor fColor;
};
struct AAMultiTextureVertex {
SkPoint fPosition;
int fTextureIdx;
SkPoint fTextureCoords;
SkPoint3 fEdges[4];
GrColor fColor;
};
// Maximum number of textures supported by this op. Must also be checked against the caps
// limit. These numbers were based on some limited experiments on a HP Z840 and Pixel XL 2016
@ -59,7 +76,7 @@ public:
}
static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt,
sk_sp<GrColorSpaceXform> csxf,
sk_sp<GrColorSpaceXform> csxf, GrAA aa,
const GrSamplerState::Filter filters[],
const GrShaderCaps& caps) {
// We use placement new to avoid always allocating space for kMaxTextures TextureSampler
@ -68,7 +85,7 @@ public:
size_t size = sizeof(TextureGeometryProcessor) + sizeof(TextureSampler) * (samplerCnt - 1);
void* mem = GrGeometryProcessor::operator new(size);
return sk_sp<TextureGeometryProcessor>(new (mem) TextureGeometryProcessor(
proxies, proxyCnt, samplerCnt, std::move(csxf), filters, caps));
proxies, proxyCnt, samplerCnt, std::move(csxf), aa, filters, caps));
}
~TextureGeometryProcessor() override {
@ -82,6 +99,7 @@ public:
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
b->add32(static_cast<uint32_t>(this->aa()));
}
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
@ -149,13 +167,36 @@ public:
&fColorSpaceXformHelper);
}
args.fFragBuilder->codeAppend(";");
args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
if (GrAA::kYes == textureGP.aa()) {
GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
GrGLSLVarying::Scope::kVertToFrag);
args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
args.fVertBuilder->codeAppendf(
R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
aaDistVarying.vsOut(), textureGP.fPositions.fName,
textureGP.fPositions.fName, textureGP.fPositions.fName,
textureGP.fPositions.fName);
args.fFragBuilder->codeAppendf(
"float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));",
aaDistVarying.fsIn(), aaDistVarying.fsIn(), aaDistVarying.fsIn(),
aaDistVarying.fsIn());
args.fFragBuilder->codeAppendf("%s = float4(clamp(mindist, 0, 1));",
args.fOutputCoverage);
} else {
args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
}
}
GrGLSLColorSpaceXformHelper fColorSpaceXformHelper;
};
return new GLSLProcessor;
}
GrAA aa() const { return GrAA(fAAEdges[0].isInitialized()); }
private:
// This exists to reduce the number of shaders generated. It does some rounding of sampler
// counts.
@ -173,10 +214,9 @@ private:
}
TextureGeometryProcessor(sk_sp<GrTextureProxy> proxies[], int proxyCnt, int samplerCnt,
sk_sp<GrColorSpaceXform> csxf, const GrSamplerState::Filter filters[],
const GrShaderCaps& caps)
: INHERITED(kTextureGeometryProcessor_ClassID)
, fColorSpaceXform(std::move(csxf)) {
sk_sp<GrColorSpaceXform> csxf, GrAA aa,
const GrSamplerState::Filter filters[], const GrShaderCaps& caps)
: INHERITED(kTextureGeometryProcessor_ClassID), fColorSpaceXform(std::move(csxf)) {
SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt);
fPositions = this->addVertexAttrib("position", kFloat2_GrVertexAttribType);
fSamplers[0].reset(std::move(proxies[0]), filters[0]);
@ -200,6 +240,12 @@ private:
}
fTextureCoords = this->addVertexAttrib("textureCoords", kFloat2_GrVertexAttribType);
if (GrAA::kYes == aa) {
fAAEdges[0] = this->addVertexAttrib("aaEdge0", kFloat3_GrVertexAttribType);
fAAEdges[1] = this->addVertexAttrib("aaEdge1", kFloat3_GrVertexAttribType);
fAAEdges[2] = this->addVertexAttrib("aaEdge2", kFloat3_GrVertexAttribType);
fAAEdges[3] = this->addVertexAttrib("aaEdge3", kFloat3_GrVertexAttribType);
}
fColors = this->addVertexAttrib("color", kUByte4_norm_GrVertexAttribType);
}
@ -207,12 +253,148 @@ private:
Attribute fTextureIdx;
Attribute fTextureCoords;
Attribute fColors;
Attribute fAAEdges[4];
sk_sp<GrColorSpaceXform> fColorSpaceXform;
TextureSampler fSamplers[1];
typedef GrGeometryProcessor INHERITED;
};
namespace {
// This is a class soley so it can be partially specialized (functions cannot be).
template<GrAA, typename Vertex> class VertexAAHandler;
template<typename Vertex> class VertexAAHandler<GrAA::kNo, Vertex> {
public:
static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad,
const SkRect& texRect) {
vertices[0].fPosition = quad.point(0);
vertices[0].fTextureCoords = {texRect.fLeft, texRect.fTop};
vertices[1].fPosition = quad.point(1);
vertices[1].fTextureCoords = {texRect.fLeft, texRect.fBottom};
vertices[2].fPosition = quad.point(2);
vertices[2].fTextureCoords = {texRect.fRight, texRect.fTop};
vertices[3].fPosition = quad.point(3);
vertices[3].fTextureCoords = {texRect.fRight, texRect.fBottom};
}
};
template<typename Vertex> class VertexAAHandler<GrAA::kYes, Vertex> {
public:
static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad,
const SkRect& texRect) {
// We compute the four edge equations for quad, then outset them and compute a new quad
// as the intersection points of the outset edges.
// GrQuad is in tristip order but we want the points to be in a fan order, so swap 2 and 3.
Sk4f xs(quad.point(0).fX, quad.point(1).fX, quad.point(3).fX, quad.point(2).fX);
Sk4f ys(quad.point(0).fY, quad.point(1).fY, quad.point(3).fY, quad.point(2).fY);
Sk4f xsrot = SkNx_shuffle<1, 2, 3, 0>(xs);
Sk4f ysrot = SkNx_shuffle<1, 2, 3, 0>(ys);
Sk4f normXs = ysrot - ys;
Sk4f normYs = xs - xsrot;
Sk4f ds = xsrot * ys - ysrot * xs;
Sk4f invNormLengths = (normXs * normXs + normYs * normYs).rsqrt();
float test = normXs[0] * xs[2] + normYs[0] * ys[2] + ds[0];
// Make sure the edge equations have their normals facing into the quad in device space
if (test < 0) {
invNormLengths = -invNormLengths;
}
normXs *= invNormLengths;
normYs *= invNormLengths;
ds *= invNormLengths;
// Here is the bloat. This makes our edge equations compute coverage without requiring a
// half pixel offset and is also used to compute the bloated quad that will cover all
// pixels.
ds += Sk4f(0.5f);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
vertices[j].fEdges[i].fX = normXs[i];
vertices[j].fEdges[i].fY = normYs[i];
vertices[j].fEdges[i].fZ = ds[i];
}
}
// Reverse the process to compute the points of the bloated quad from the edge equations.
// This time the inputs don't have 1s as their third coord and we want to homogenize rather
// than normalize the output since we need a GrQuad with 2D points.
xsrot = SkNx_shuffle<3, 0, 1, 2>(normXs);
ysrot = SkNx_shuffle<3, 0, 1, 2>(normYs);
Sk4f dsrot = SkNx_shuffle<3, 0, 1, 2>(ds);
xs = ysrot * ds - normYs * dsrot;
ys = normXs * dsrot - xsrot * ds;
ds = xsrot * normYs - ysrot * normXs;
ds = ds.invert();
xs *= ds;
ys *= ds;
// Go back to tri strip order when writing out the bloated quad to vertex positions.
vertices[0].fPosition = {xs[0], ys[0]};
vertices[1].fPosition = {xs[1], ys[1]};
vertices[3].fPosition = {xs[2], ys[2]};
vertices[2].fPosition = {xs[3], ys[3]};
AssignTexCoords(vertices, quad, texRect);
}
private:
static void AssignTexCoords(Vertex* vertices, const GrQuad& quad, const SkRect& tex) {
SkMatrix q = SkMatrix::MakeAll(quad.point(0).fX, quad.point(1).fX, quad.point(2).fX,
quad.point(0).fY, quad.point(1).fY, quad.point(2).fY,
1.f, 1.f, 1.f);
SkMatrix qinv;
if (!q.invert(&qinv)) {
return;
}
SkMatrix t = SkMatrix::MakeAll(tex.fLeft, tex.fLeft, tex.fRight,
tex.fTop, tex.fBottom, tex.fTop,
1.f, 1.f, 1.f);
SkMatrix map;
map.setConcat(t, qinv);
SkMatrixPriv::MapPointsWithStride(map, &vertices[0].fTextureCoords, sizeof(Vertex),
&vertices[0].fPosition, sizeof(Vertex), 4);
}
};
template <typename Vertex, bool IsMultiTex> struct TexIdAssigner;
template <typename Vertex> struct TexIdAssigner<Vertex, true> {
static void Assign(Vertex* vertices, int textureIdx) {
vertices[0].fTextureIdx = textureIdx;
vertices[1].fTextureIdx = textureIdx;
vertices[2].fTextureIdx = textureIdx;
vertices[3].fTextureIdx = textureIdx;
}
};
template <typename Vertex> struct TexIdAssigner<Vertex, false> {
static void Assign(Vertex* vertices, int textureIdx) {}
};
} // anonymous namespace
template <typename Vertex, bool IsMultiTex, GrAA AA>
static void tessellate_quad(const GrQuad& devQuad, const SkRect& srcRect, GrColor color,
GrSurfaceOrigin origin, Vertex* vertices, SkScalar iw, SkScalar ih,
int textureIdx) {
SkRect texRect = {
iw * srcRect.fLeft,
ih * srcRect.fTop,
iw * srcRect.fRight,
ih * srcRect.fBottom
};
if (origin == kBottomLeft_GrSurfaceOrigin) {
texRect.fTop = 1.f - texRect.fTop;
texRect.fBottom = 1.f - texRect.fBottom;
}
VertexAAHandler<AA, Vertex>::AssignPositionsAndTexCoords(vertices, devQuad, texRect);
vertices[0].fColor = color;
vertices[1].fColor = color;
vertices[2].fColor = color;
vertices[3].fColor = color;
TexIdAssigner<Vertex, IsMultiTex>::Assign(vertices, textureIdx);
}
/**
* Op that implements GrTextureOp::Make. It draws textured quads. Each quad can modulate against a
* the texture by color. The blend with the destination is always src-over. The edges are non-AA.
@ -221,11 +403,11 @@ class TextureOp final : public GrMeshDrawOp {
public:
static std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy,
GrSamplerState::Filter filter, GrColor color,
const SkRect srcRect, const SkRect dstRect,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf,
bool allowSRBInputs) {
return std::unique_ptr<GrDrawOp>(new TextureOp(std::move(proxy), filter, color, srcRect,
dstRect, viewMatrix, std::move(csxf),
dstRect, aa, viewMatrix, std::move(csxf),
allowSRBInputs));
}
@ -298,22 +480,23 @@ private:
#if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007
__attribute__((no_sanitize("float-cast-overflow")))
#endif
size_t RectSizeAsSizeT(const SkRect &rect) {;
size_t RectSizeAsSizeT(const SkRect& rect) {;
return static_cast<size_t>(SkTMax(rect.width(), 1.f) * SkTMax(rect.height(), 1.f));
}
static constexpr int kMaxTextures = TextureGeometryProcessor::kMaxTextures;
TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color,
const SkRect& srcRect, const SkRect& dstRect, const SkMatrix& viewMatrix,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> csxf, bool allowSRGBInputs)
: INHERITED(ClassID())
, fColorSpaceXform(std::move(csxf))
, fProxy0(proxy.release())
, fFilter0(filter)
, fProxyCnt(1)
, fFinalized(false)
, fAllowSRGBInputs(allowSRGBInputs) {
, fAA(aa == GrAA::kYes ? 1 : 0)
, fFinalized(0)
, fAllowSRGBInputs(allowSRGBInputs ? 1 : 0) {
Draw& draw = fDraws.push_back();
draw.fSrcRect = srcRect;
draw.fTextureIdx = 0;
@ -339,7 +522,7 @@ __attribute__((no_sanitize("float-cast-overflow")))
sk_sp<GrGeometryProcessor> gp =
TextureGeometryProcessor::Make(proxiesSPs, fProxyCnt, std::move(fColorSpaceXform),
filters, *target->caps().shaderCaps());
this->aa(), filters, *target->caps().shaderCaps());
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
@ -356,35 +539,28 @@ __attribute__((no_sanitize("float-cast-overflow")))
return;
}
if (1 == fProxyCnt) {
SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::Vertex));
for (int i = 0; i < fDraws.count(); ++i) {
auto vertices = static_cast<TextureGeometryProcessor::Vertex*>(vdata);
GrTexture* texture = proxies[0]->priv().peekTexture();
float iw = 1.f / texture->width();
float ih = 1.f / texture->height();
float tl = iw * fDraws[i].fSrcRect.fLeft;
float tr = iw * fDraws[i].fSrcRect.fRight;
float tt = ih * fDraws[i].fSrcRect.fTop;
float tb = ih * fDraws[i].fSrcRect.fBottom;
if (proxies[0]->origin() == kBottomLeft_GrSurfaceOrigin) {
tt = 1.f - tt;
tb = 1.f - tb;
GrSurfaceOrigin origin = proxies[0]->origin();
GrTexture* texture = proxies[0]->priv().peekTexture();
float iw = 1.f / texture->width();
float ih = 1.f / texture->height();
if (GrAA::kYes == this->aa()) {
SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::AAVertex));
auto vertices = static_cast<TextureGeometryProcessor::AAVertex*>(vdata);
for (int i = 0; i < fDraws.count(); ++i) {
tessellate_quad<TextureGeometryProcessor::AAVertex, false, GrAA::kYes>(
fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
vertices + 4 * i, iw, ih, 0);
}
} else {
SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::Vertex));
auto vertices = static_cast<TextureGeometryProcessor::Vertex*>(vdata);
for (int i = 0; i < fDraws.count(); ++i) {
tessellate_quad<TextureGeometryProcessor::Vertex, false, GrAA::kNo>(
fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
vertices + 4 * i, iw, ih, 0);
}
vertices[0 + 4 * i].fPosition = fDraws[i].fQuad.points()[0];
vertices[0 + 4 * i].fTextureCoords = {tl, tt};
vertices[0 + 4 * i].fColor = fDraws[i].fColor;
vertices[1 + 4 * i].fPosition = fDraws[i].fQuad.points()[1];
vertices[1 + 4 * i].fTextureCoords = {tl, tb};
vertices[1 + 4 * i].fColor = fDraws[i].fColor;
vertices[2 + 4 * i].fPosition = fDraws[i].fQuad.points()[2];
vertices[2 + 4 * i].fTextureCoords = {tr, tt};
vertices[2 + 4 * i].fColor = fDraws[i].fColor;
vertices[3 + 4 * i].fPosition = fDraws[i].fQuad.points()[3];
vertices[3 + 4 * i].fTextureCoords = {tr, tb};
vertices[3 + 4 * i].fColor = fDraws[i].fColor;
}
} else {
SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::MultiTextureVertex));
GrTexture* textures[kMaxTextures];
float iw[kMaxTextures];
float ih[kMaxTextures];
@ -393,33 +569,29 @@ __attribute__((no_sanitize("float-cast-overflow")))
iw[t] = 1.f / textures[t]->width();
ih[t] = 1.f / textures[t]->height();
}
for (int i = 0; i < fDraws.count(); ++i) {
int t = fDraws[i].fTextureIdx;
auto vertices = static_cast<TextureGeometryProcessor::MultiTextureVertex*>(vdata);
float tl = iw[t] * fDraws[i].fSrcRect.fLeft;
float tr = iw[t] * fDraws[i].fSrcRect.fRight;
float tt = ih[t] * fDraws[i].fSrcRect.fTop;
float tb = ih[t] * fDraws[i].fSrcRect.fBottom;
if (proxies[t]->origin() == kBottomLeft_GrSurfaceOrigin) {
tt = 1.f - tt;
tb = 1.f - tb;
if (GrAA::kYes == this->aa()) {
SkASSERT(gp->getVertexStride() ==
sizeof(TextureGeometryProcessor::AAMultiTextureVertex));
auto vertices = static_cast<TextureGeometryProcessor::AAMultiTextureVertex*>(vdata);
for (int i = 0; i < fDraws.count(); ++i) {
auto tidx = fDraws[i].fTextureIdx;
GrSurfaceOrigin origin = proxies[tidx]->origin();
tessellate_quad<TextureGeometryProcessor::AAMultiTextureVertex, true,
GrAA::kYes>(fDraws[i].fQuad, fDraws[i].fSrcRect,
fDraws[i].fColor, origin, vertices + 4 * i,
iw[tidx], ih[tidx], tidx);
}
} else {
SkASSERT(gp->getVertexStride() ==
sizeof(TextureGeometryProcessor::MultiTextureVertex));
auto vertices = static_cast<TextureGeometryProcessor::MultiTextureVertex*>(vdata);
for (int i = 0; i < fDraws.count(); ++i) {
auto tidx = fDraws[i].fTextureIdx;
GrSurfaceOrigin origin = proxies[tidx]->origin();
tessellate_quad<TextureGeometryProcessor::MultiTextureVertex, true, GrAA::kNo>(
fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
vertices + 4 * i, iw[tidx], ih[tidx], tidx);
}
vertices[0 + 4 * i].fPosition = fDraws[i].fQuad.points()[0];
vertices[0 + 4 * i].fTextureIdx = t;
vertices[0 + 4 * i].fTextureCoords = {tl, tt};
vertices[0 + 4 * i].fColor = fDraws[i].fColor;
vertices[1 + 4 * i].fPosition = fDraws[i].fQuad.points()[1];
vertices[1 + 4 * i].fTextureIdx = t;
vertices[1 + 4 * i].fTextureCoords = {tl, tb};
vertices[1 + 4 * i].fColor = fDraws[i].fColor;
vertices[2 + 4 * i].fPosition = fDraws[i].fQuad.points()[2];
vertices[2 + 4 * i].fTextureIdx = t;
vertices[2 + 4 * i].fTextureCoords = {tr, tt};
vertices[2 + 4 * i].fColor = fDraws[i].fColor;
vertices[3 + 4 * i].fPosition = fDraws[i].fQuad.points()[3];
vertices[3 + 4 * i].fTextureIdx = t;
vertices[3 + 4 * i].fTextureCoords = {tr, tb};
vertices[3 + 4 * i].fColor = fDraws[i].fColor;
}
}
GrPrimitiveType primitiveType =
@ -446,6 +618,9 @@ __attribute__((no_sanitize("float-cast-overflow")))
if (!GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())) {
return false;
}
if (this->fAA != that->fAA) {
return false;
}
// Because of an issue where GrColorSpaceXform adds the same function every time it is used
// in a texture lookup, we only allow multiple textures when there is no transform.
if (TextureGeometryProcessor::SupportsMultitexture(shaderCaps) && !fColorSpaceXform &&
@ -560,6 +735,8 @@ __attribute__((no_sanitize("float-cast-overflow")))
return newProxyCnt;
}
GrAA aa() const { return static_cast<GrAA>(fAA); }
GrTextureProxy* const* proxies() const { return fProxyCnt > 1 ? fProxyArray : &fProxy0; }
const GrSamplerState::Filter* filters() const {
@ -585,12 +762,12 @@ __attribute__((no_sanitize("float-cast-overflow")))
GrTextureProxy** fProxyArray;
};
size_t fMaxApproxDstPixelArea;
// The next four members should pack.
GrSamplerState::Filter fFilter0;
uint8_t fProxyCnt;
unsigned fAA : 1;
// Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
uint8_t fFinalized;
uint8_t fAllowSRGBInputs;
unsigned fFinalized : 1;
unsigned fAllowSRGBInputs : 1;
typedef GrMeshDrawOp INHERITED;
};
@ -603,11 +780,11 @@ constexpr int TextureOp::kMaxTextures;
namespace GrTextureOp {
std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter,
GrColor color, const SkRect& srcRect, const SkRect& dstRect,
GrColor color, const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf,
bool allowSRGBInputs) {
SkASSERT(!viewMatrix.hasPerspective());
return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, viewMatrix,
return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, aa, viewMatrix,
std::move(csxf), allowSRGBInputs);
}
@ -639,7 +816,8 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) {
static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
auto csxf = GrTest::TestColorXform(random);
bool allowSRGBInputs = random->nextBool();
return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, viewMatrix,
GrAA aa = GrAA(random->nextBool());
return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, aa, viewMatrix,
std::move(csxf), allowSRGBInputs);
}

View File

@ -23,7 +23,7 @@ namespace GrTextureOp {
* space. 'viewMatrix' must be affine.
*/
std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy>, GrSamplerState::Filter, GrColor,
const SkRect& srcRect, const SkRect& dstRect,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>,
bool allowSRGBInputs);
}