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:
parent
ac47b88d3c
commit
b5ef1f9b13
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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>);
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user