Reland "Move GrGeometryProcessor's textures out of classes and into"

This reverts commit fdf05f4ff4.

Reason for revert: Android fixed after removing multitexture support from TextureOp.

Original change's description:
> Revert "Move GrGeometryProcessor's textures out of classes and into"
> 
> This reverts commit af87483873.
> 
> Revert "GrGeometryProcessor derives from GrNonAtomicRef not GrProgramElement."
> 
> This reverts commit 607be37e3d.
> 
> Revert "Store GrMeshDrawOps' meshes in GrOpFlushState's arena."
> 
> This reverts commit b948572c78.
> 
> Revert "Remove multitexturing support from GrTextureOp."
> 
> This reverts commit 986f64c601.
> 
> Revert "Make result of GrOp::combineIfPossible be an enum."
> 
> This reverts commit 641ac7daa8.
> 
> Bug: b/112244393
> Change-Id: I579491a3f2f2f2093f1e2a6141fa1e4cc7b760a4
> Reviewed-on: https://skia-review.googlesource.com/145646
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=bsalomon@google.com

Change-Id: I1d41c2ecf7862e31fb025a7a00bb07bae9d83a47
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: b/112244393
Reviewed-on: https://skia-review.googlesource.com/145780
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-08-07 14:02:38 +00:00 committed by Skia Commit-Bot
parent 0d794288d1
commit 7eae3e04e3
86 changed files with 1050 additions and 1422 deletions

View File

@ -0,0 +1,99 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkImage.h"
#include "SkRandom.h"
#include "SkSurface.h"
/**
* Simulates drawing layers images in a grid a la a tile based compositor. The layers are all
* untransformed.
*/
class CompositingImages : public Benchmark {
public:
CompositingImages(SkISize tileSize, SkISize tileGridSize, int layerCnt)
: fTileSize(tileSize), fTileGridSize(tileGridSize), fLayerCnt(layerCnt) {
fName.appendf("compositing_images_tile_size_%dx%d_tile_cnt_%dx%d_layers_%d",
fTileSize.fWidth, fTileSize.fHeight, fTileGridSize.fWidth,
fTileGridSize.fHeight, fLayerCnt);
}
bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
protected:
const char* onGetName() override { return fName.c_str(); }
void onPerCanvasPreDraw(SkCanvas* canvas) override {
auto ii = SkImageInfo::Make(fTileSize.fWidth, fTileSize.fHeight, kRGBA_8888_SkColorType,
kPremul_SkAlphaType, nullptr);
SkRandom random;
int numImages = fLayerCnt * fTileGridSize.fWidth * fTileGridSize.fHeight;
fImages.reset(new sk_sp<SkImage>[numImages]);
for (int i = 0; i < numImages; ++i) {
auto surf = canvas->makeSurface(ii);
SkColor color = random.nextU();
surf->getCanvas()->clear(color);
SkPaint paint;
paint.setColor(~color);
paint.setBlendMode(SkBlendMode::kSrc);
surf->getCanvas()->drawRect(
SkRect::MakeLTRB(3, 3, fTileSize.fWidth - 3, fTileSize.fHeight - 3), paint);
fImages[i] = surf->makeImageSnapshot();
}
}
void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); }
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
paint.setFilterQuality(kNone_SkFilterQuality);
// TODO: Use per-edge AA flags for tiles when API available.
paint.setAntiAlias(true);
for (int i = 0; i < loops; ++i) {
int imgIdx = 0;
for (int l = 0; l < fLayerCnt; ++l) {
for (int y = 0; y < fTileGridSize.fHeight; ++y) {
for (int x = 0; x < fTileGridSize.fWidth; ++x) {
canvas->drawImage(fImages[imgIdx++].get(), x * fTileSize.fWidth,
y * fTileSize.fHeight, &paint);
}
}
}
// Prevent any batching between composited "frames".
canvas->flush();
}
}
private:
SkIPoint onGetSize() override {
return SkIPoint::Make(fTileSize.fWidth * fTileGridSize.fWidth,
fTileSize.fHeight * fTileGridSize.fHeight);
}
std::unique_ptr<sk_sp<SkImage>[]> fImages;
SkString fName;
SkISize fTileSize;
SkISize fTileGridSize;
int fLayerCnt;
typedef Benchmark INHERITED;
};
DEF_BENCH(return new CompositingImages({256, 256}, {8, 8}, 1));
DEF_BENCH(return new CompositingImages({512, 512}, {4, 4}, 1));
DEF_BENCH(return new CompositingImages({1024, 512}, {2, 4}, 1));
DEF_BENCH(return new CompositingImages({256, 256}, {8, 8}, 4));
DEF_BENCH(return new CompositingImages({512, 512}, {4, 4}, 4));
DEF_BENCH(return new CompositingImages({1024, 512}, {2, 4}, 4));
DEF_BENCH(return new CompositingImages({256, 256}, {8, 8}, 16));
DEF_BENCH(return new CompositingImages({512, 512}, {4, 4}, 16));
DEF_BENCH(return new CompositingImages({1024, 512}, {2, 4}, 16));

94
bench/ImageCycleBench.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkImage.h"
#include "SkRandom.h"
#include "SkSurface.h"
/**
* Draws a small set of small images multiple times each with no overlaps so that each image could
* be batched. This was originally added to detect regressions as GrTextureOp is refactored to
* use "dynamic state" for texture bindings. Everything is kept small as we're mostly interested in
* CPU overhead.
*/
class ImageCycle : public Benchmark {
public:
/**
* imageCnt is the number of images and repeat cnt is how many times each image is drawn per
* logical "frame."
*/
ImageCycle(int imageCnt, int repeatCnt) : fImageCnt(imageCnt), fRepeatCnt(repeatCnt) {
fName.appendf("image_cycle_image_cnt_%d_repeat_cnt_%d", fImageCnt, fRepeatCnt);
}
bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
protected:
const char* onGetName() override { return fName.c_str(); }
void onPerCanvasPreDraw(SkCanvas* canvas) override {
auto ii = SkImageInfo::Make(kImageSize.fWidth, kImageSize.fHeight, kRGBA_8888_SkColorType,
kPremul_SkAlphaType, nullptr);
SkRandom random;
fImages.reset(new sk_sp<SkImage>[fImageCnt]);
for (int i = 0; i < fImageCnt; ++i) {
auto surf = canvas->makeSurface(ii);
SkColor color = random.nextU();
surf->getCanvas()->clear(color);
SkPaint paint;
paint.setColor(~color);
paint.setBlendMode(SkBlendMode::kSrc);
surf->getCanvas()->drawRect(
SkRect::MakeLTRB(1, 1, kImageSize.fWidth - 1, kImageSize.fHeight - 1), paint);
fImages[i] = surf->makeImageSnapshot();
}
}
void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); }
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
paint.setFilterQuality(kNone_SkFilterQuality);
paint.setAntiAlias(true);
static constexpr SkScalar kPad = 2;
// To avoid tripping up bounds tracking we position the draws such that all the
// draws of image 0 are above those of image 1, etc.
static const int imagesPerRow =
SkScalarFloorToInt(kDeviceSize.fWidth / (kImageSize.fWidth + kPad));
int rowsPerImage = SkScalarCeilToInt((SkScalar)fRepeatCnt / imagesPerRow);
for (int l = 0; l < loops; ++l) {
for (int r = 0; r < fRepeatCnt; ++r) {
for (int i = 0; i < fImageCnt; ++i) {
SkScalar imageYOffset = i * rowsPerImage * (kImageSize.fHeight + kPad);
SkScalar rowYOffset = (r / imagesPerRow) * (kImageSize.fHeight + kPad);
SkScalar x = (r % imagesPerRow) * (kImageSize.fWidth + kPad);
canvas->drawImage(fImages[i].get(), x, imageYOffset + rowYOffset, &paint);
}
}
// Prevent any batching between "frames".
canvas->flush();
}
}
private:
SkIPoint onGetSize() override { return {kDeviceSize.fWidth, kDeviceSize.fHeight}; }
static constexpr SkISize kImageSize{4, 4};
static constexpr SkISize kDeviceSize{64, 64};
std::unique_ptr<sk_sp<SkImage>[]> fImages;
SkString fName;
int fImageCnt;
int fRepeatCnt;
typedef Benchmark INHERITED;
};
DEF_BENCH(return new ImageCycle(5, 10));

View File

@ -1,136 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "GrContextOptions.h"
#include "SkCanvas.h"
#include "SkImage.h"
#include "SkRandom.h"
#include "SkSurface.h"
class MultitextureImages : public Benchmark {
public:
MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing, bool aa)
: fImageSize(imageSize)
, fDstRectSize(dstRectSize)
, 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");
}
}
bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
protected:
const char* onGetName() override { return fName.c_str(); }
void onPerCanvasPreDraw(SkCanvas* canvas) override {
auto ii = SkImageInfo::Make(fImageSize, fImageSize, kRGBA_8888_SkColorType,
kPremul_SkAlphaType, nullptr);
SkRandom random;
for (int i = 0; i < kNumImages; ++i) {
auto surf = canvas->makeSurface(ii);
SkColor color = random.nextU();
surf->getCanvas()->clear(color);
SkPaint paint;
paint.setColor(~color);
paint.setBlendMode(SkBlendMode::kSrc);
surf->getCanvas()->drawRect(SkRect::MakeLTRB(3, 3, fImageSize - 3, fImageSize - 3),
paint);
fImages[i] = surf->makeImageSnapshot();
}
}
void onPerCanvasPostDraw(SkCanvas*) override {
for (int i = 0; i < kNumImages; ++i) {
fImages[i].reset();
}
}
void onDraw(int loops, SkCanvas* canvas) override {
SkRect rect = SkRect::MakeWH(fDstRectSize, fDstRectSize);
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);
canvas->drawImageRect(fImages[j].get(), rect.makeOffset(translate.fX, translate.fY),
&paint);
}
// Prevent any batching except without multitexturing since we're trying to measure
// drawing distinct images and just repeating images here to increase the workload for
// timing reasons.
canvas->flush();
}
}
void modifyGrContextOptions(GrContextOptions* options) override {
options->fDisableImageMultitexturing = fDisableMultitexturing;
}
private:
SkIPoint onGetSize() override {
// The rows and columns are spaced by kTranslate, but the images may overlap if they are
// larger than kTranslate and extend beyond the last row/column.
return SkIPoint::Make(kTranslate * (kNumColumns - 1) + fDstRectSize,
kTranslate * (kNumRows - 1) + fDstRectSize);
}
SkVector translation(int i) const {
SkVector offset;
// 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;
}
static const int kTranslate = 200;
static const int kNumColumns = 5;
static const int kNumRows = 5;
static const int kNumImages = 8;
sk_sp<SkImage> fImages[kNumImages];
SkString fName;
int fImageSize;
int fDstRectSize;
bool fDisableMultitexturing;
bool fAA;
typedef Benchmark INHERITED;
};
// 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, 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));

View File

@ -152,8 +152,6 @@ public:
private:
friend class ::GrOpMemoryPool;
bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
void onPrepareDraws(Target* target) override {
sk_sp<GrGeometryProcessor> gp(new GP(fMode, fColorSpaceXform));
@ -199,12 +197,12 @@ private:
}
}
GrMesh mesh(GrPrimitiveType::kTriangleStrip);
mesh.setNonIndexedNonInstanced(kVertexCount);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangleStrip);
mesh->setNonIndexedNonInstanced(kVertexCount);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = target->makePipeline(0, GrProcessorSet::MakeEmptySet(),
target->detachAppliedClip());
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
Mode fMode;

View File

@ -40,7 +40,8 @@ public:
}
protected:
BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
BezierTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
int32_t classID)
: INHERITED(classID)
, fRect(rect)
, fColor(color)
@ -53,17 +54,15 @@ protected:
return target->makePipeline(0, std::move(fProcessorSet), target->detachAppliedClip());
}
const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
sk_sp<const GrGeometryProcessor> gp() const { return fGeometryProcessor; }
const SkRect& rect() const { return fRect; }
GrColor color() const { return fColor; }
private:
bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
SkRect fRect;
GrColor fColor;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
sk_sp<const GrGeometryProcessor> fGeometryProcessor;
GrProcessorSet fProcessorSet;
typedef GrMeshDrawOp INHERITED;
@ -76,7 +75,7 @@ public:
const char* name() const override { return "BezierCubicTestOp"; }
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
sk_sp<GrGeometryProcessor> gp,
sk_sp<const GrGeometryProcessor> gp,
const SkRect& rect,
GrColor color) {
GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
@ -87,13 +86,13 @@ public:
private:
friend class ::GrOpMemoryPool; // for ctor
BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
BezierCubicTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
: INHERITED(std::move(gp), rect, color, ClassID()) {}
void onPrepareDraws(Target* target) override {
QuadHelper helper;
SkASSERT(this->gp()->debugOnly_vertexStride() == sizeof(SkPoint));
SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, sizeof(SkPoint), 1));
QuadHelper helper(target, sizeof(SkPoint), 1);
SkPoint* pts = reinterpret_cast<SkPoint*>(helper.vertices());
if (!pts) {
return;
}
@ -261,7 +260,7 @@ public:
const char* name() const override { return "BezierConicTestOp"; }
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
sk_sp<GrGeometryProcessor> gp,
sk_sp<const GrGeometryProcessor> gp,
const SkRect& rect,
GrColor color,
const SkMatrix& klm) {
@ -273,7 +272,7 @@ public:
private:
friend class ::GrOpMemoryPool; // for ctor
BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
BezierConicTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
const SkMatrix& klm)
: INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
@ -283,9 +282,9 @@ private:
};
void onPrepareDraws(Target* target) override {
QuadHelper helper;
SkASSERT(this->gp()->debugOnly_vertexStride() == sizeof(Vertex));
Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, sizeof(Vertex), 1));
QuadHelper helper(target, sizeof(Vertex), 1);
Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
if (!verts) {
return;
}
@ -483,7 +482,7 @@ public:
const char* name() const override { return "BezierQuadTestOp"; }
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
sk_sp<GrGeometryProcessor> gp,
sk_sp<const GrGeometryProcessor> gp,
const SkRect& rect,
GrColor color,
const GrPathUtils::QuadUVMatrix& devToUV) {
@ -495,7 +494,7 @@ public:
private:
friend class ::GrOpMemoryPool; // for ctor
BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
BezierQuadTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
const GrPathUtils::QuadUVMatrix& devToUV)
: INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
@ -505,9 +504,9 @@ private:
};
void onPrepareDraws(Target* target) override {
QuadHelper helper;
SkASSERT(this->gp()->debugOnly_vertexStride() == sizeof(Vertex));
Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, sizeof(Vertex), 1));
QuadHelper helper(target, sizeof(Vertex), 1);
Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
if (!verts) {
return;
}

View File

@ -108,7 +108,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* flushState) override {
SkPoint vertices[4] = {

View File

@ -87,8 +87,8 @@ private:
SkMatrix::I()));
SkASSERT(gp->debugOnly_vertexStride() == sizeof(SkPoint));
QuadHelper helper;
SkPoint* verts = reinterpret_cast<SkPoint*>(helper.init(target, sizeof(SkPoint), 1));
QuadHelper helper(target, sizeof(SkPoint), 1);
SkPoint* verts = reinterpret_cast<SkPoint*>(helper.vertices());
if (!verts) {
return;
}
@ -96,11 +96,9 @@ private:
SkPointPriv::SetRectTriStrip(verts, fRect, sizeof(SkPoint));
auto pipe = target->makePipeline(0, std::move(fProcessors), target->detachAppliedClip());
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
GrColor fColor;
GrProcessorSet fProcessors;
SkRect fRect;

View File

@ -34,6 +34,7 @@ bench_sources = [
"$_bench/ColorCanvasDrawBitmapBench.cpp",
"$_bench/ColorFilterBench.cpp",
"$_bench/ColorPrivBench.cpp",
"$_bench/CompositingImagesBench.cpp",
"$_bench/ControlBench.cpp",
"$_bench/CoverageBench.cpp",
"$_bench/CubicKLMBench.cpp",
@ -60,6 +61,7 @@ bench_sources = [
"$_bench/ImageBench.cpp",
"$_bench/ImageCacheBench.cpp",
"$_bench/ImageCacheBudgetBench.cpp",
"$_bench/ImageCycleBench.cpp",
"$_bench/ImageFilterCollapse.cpp",
"$_bench/ImageFilterDAGBench.cpp",
"$_bench/InterpBench.cpp",
@ -75,7 +77,6 @@ bench_sources = [
"$_bench/MergeBench.cpp",
"$_bench/MipMapBench.cpp",
"$_bench/MorphologyBench.cpp",
"$_bench/MultitextureImageBench.cpp",
"$_bench/MutexBench.cpp",
"$_bench/PatchBench.cpp",
"$_bench/PathBench.cpp",

View File

@ -125,7 +125,6 @@ skia_gpu_sources = [
"$_src/gpu/GrPathUtils.cpp",
"$_src/gpu/GrPathUtils.h",
"$_src/gpu/GrPendingIOResource.h",
"$_src/gpu/GrPendingProgramElement.h",
"$_src/gpu/GrOnFlushResourceProvider.cpp",
"$_src/gpu/GrOnFlushResourceProvider.h",
"$_src/gpu/GrPipeline.cpp",
@ -136,7 +135,6 @@ skia_gpu_sources = [
"$_src/gpu/GrProcessorSet.h",
"$_src/gpu/GrProgramDesc.cpp",
"$_src/gpu/GrProgramDesc.h",
"$_src/gpu/GrProgramElement.h",
"$_src/gpu/GrProcessor.cpp",
"$_src/gpu/GrProcessor.h",
"$_src/gpu/GrProcessorAnalysis.cpp",

View File

@ -80,8 +80,10 @@ public:
fProxy = nullptr;
}
/** Called by owning GrProgramElement when the program element is first scheduled for
execution. It can only be called once. */
/**
* Called when transferring into an op list and therefore scheduled for an IO operation. It can
* only be called once.
*/
void markPendingIO() const {
// This should only be called when the owning GrProgramElement gets its first
// pendingExecution ref.

View File

@ -240,6 +240,9 @@ public:
SkASSERT(LazyState::kFully != this->lazyInstantiationState());
return fHeight;
}
SkISize isize() const { return {fWidth, fHeight}; }
int worstCaseWidth() const;
int worstCaseHeight() const;
/**

View File

@ -89,7 +89,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState*) override;

View File

@ -181,7 +181,7 @@ void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<Gr
int n = SkTMin(kMaxBatchLookBack, fOps.count());
for (int i = 0; i < n; ++i) {
GrAtlasTextOp* other = fOps.fromBack(i).get();
if (other->combineIfPossible(op.get(), caps)) {
if (other->combineIfPossible(op.get(), caps) == GrOp::CombineResult::kMerged) {
fOpMemoryPool->release(std::move(op));
return;
}

View File

@ -44,9 +44,14 @@ bool GrGpuRTCommandBuffer::draw(const GrPrimitiveProcessor& primProc, const GrPi
auto resourceProvider = this->gpu()->getContext()->contextPriv().resourceProvider();
if (pipeline.isBad() || !primProc.instantiate(resourceProvider)) {
if (pipeline.isBad()) {
return false;
}
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
if (!fixedDynamicState->fPrimitiveProcessorTextures[i]->instantiate(resourceProvider)) {
return false;
}
}
if (primProc.numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
this->gpu()->stats()->incNumFailedDraws();

View File

@ -21,12 +21,12 @@ class GrPrimitiveProcessor;
*/
class GrMesh {
public:
GrMesh(GrPrimitiveType primitiveType)
: fPrimitiveType(primitiveType)
, fBaseVertex(0) {
GrMesh(GrPrimitiveType primitiveType = GrPrimitiveType::kTriangles)
: fPrimitiveType(primitiveType), fBaseVertex(0) {
SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
}
void setPrimitiveType(GrPrimitiveType type) { fPrimitiveType = type; }
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }

View File

@ -45,8 +45,7 @@ void GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp(uint32_t opID, const Sk
SkASSERT(fCurrDraw->fPipeline->proxy() == this->drawOpArgs().fProxy);
this->rtCommandBuffer()->draw(*fCurrDraw->fGeometryProcessor, *fCurrDraw->fPipeline,
fCurrDraw->fFixedDynamicState, fCurrDraw->fDynamicStateArrays,
fMeshes.begin() + fCurrMesh, fCurrDraw->fMeshCnt, opBounds);
fCurrMesh += fCurrDraw->fMeshCnt;
fCurrDraw->fMeshes, fCurrDraw->fMeshCnt, opBounds);
fTokenTracker->flushToken();
++fCurrDraw;
}
@ -61,7 +60,6 @@ void GrOpFlushState::preExecuteDraws() {
// Setup execution iterators.
fCurrDraw = fDraws.begin();
fCurrUpload = fInlineUploads.begin();
fCurrMesh = 0;
}
void GrOpFlushState::reset() {
@ -73,8 +71,6 @@ void GrOpFlushState::reset() {
fASAPUploads.reset();
fInlineUploads.reset();
fDraws.reset();
fMeshes.reset();
fCurrMesh = 0;
fBaseDrawToken = GrDeferredUploadToken::AlreadyFlushedToken();
}
@ -104,36 +100,23 @@ GrDeferredUploadToken GrOpFlushState::addASAPUpload(GrDeferredTextureUploadFn&&
return fTokenTracker->nextTokenToFlush();
}
void GrOpFlushState::draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline,
void GrOpFlushState::draw(sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState,
const GrMesh& mesh) {
const GrMesh meshes[], int meshCnt) {
SkASSERT(fOpArgs);
SkASSERT(fOpArgs->fOp);
fMeshes.push_back(mesh);
bool firstDraw = fDraws.begin() == fDraws.end();
if (!firstDraw) {
Draw& lastDraw = *fDraws.begin();
// If the last draw shares a geometry processor and pipeline and there are no intervening
// uploads, add this mesh to it.
// Note, we could attempt to convert fixed dynamic states into dynamic state arrays here
// if everything else is equal. Maybe it's better to rely on Ops to do that?
if (lastDraw.fGeometryProcessor == gp && lastDraw.fPipeline == pipeline &&
lastDraw.fFixedDynamicState == fixedDynamicState) {
if (fInlineUploads.begin() == fInlineUploads.end() ||
fInlineUploads.tail()->fUploadBeforeToken != fTokenTracker->nextDrawToken()) {
++lastDraw.fMeshCnt;
return;
}
}
}
auto& draw = fDraws.append(&fArena);
GrDeferredUploadToken token = fTokenTracker->issueDrawToken();
draw.fGeometryProcessor.reset(gp);
for (int i = 0; i < gp->numTextureSamplers(); ++i) {
fixedDynamicState->fPrimitiveProcessorTextures[i]->addPendingRead();
}
draw.fGeometryProcessor = std::move(gp);
draw.fPipeline = pipeline;
draw.fFixedDynamicState = fixedDynamicState;
draw.fDynamicStateArrays = nullptr;
draw.fMeshCnt = 1;
draw.fMeshes = meshes;
draw.fMeshCnt = meshCnt;
draw.fOpID = fOpArgs->fOp->uniqueID();
if (firstDraw) {
fBaseDrawToken = token;

View File

@ -73,9 +73,11 @@ public:
GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) final;
/** Overrides of GrMeshDrawOp::Target. */
void draw(const GrGeometryProcessor*, const GrPipeline*, const GrPipeline::FixedDynamicState*,
const GrMesh&) final;
void draw(sk_sp<const GrGeometryProcessor>,
const GrPipeline*,
const GrPipeline::FixedDynamicState*,
const GrMesh[],
int meshCount) final;
void* makeVertexSpace(size_t vertexSize, int vertexCount, const GrBuffer**,
int* startVertex) final;
uint16_t* makeIndexSpace(int indexCount, const GrBuffer**, int* startIndex) final;
@ -118,12 +120,18 @@ private:
// that share a geometry processor into a Draw is that it allows the Gpu object to setup
// the shared state once and then issue draws for each mesh.
struct Draw {
int fMeshCnt = 0;
GrPendingProgramElement<const GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
~Draw() {
for (int i = 0; i < fGeometryProcessor->numTextureSamplers(); ++i) {
fFixedDynamicState->fPrimitiveProcessorTextures[i]->completedRead();
}
}
sk_sp<const GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline = nullptr;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
const GrPipeline::DynamicStateArrays* fDynamicStateArrays;
uint32_t fOpID;
const GrMesh* fMeshes = nullptr;
int fMeshCnt = 0;
uint32_t fOpID = SK_InvalidUniqueID;
};
// Storage for ops' pipelines, draws, and inline uploads.
@ -137,9 +145,6 @@ private:
SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads;
SkArenaAllocList<InlineUpload> fInlineUploads;
SkArenaAllocList<Draw> fDraws;
// TODO: These should go in the arena. However, GrGpuCommandBuffer and other classes currently
// accept contiguous arrays of meshes.
SkSTArray<16, GrMesh> fMeshes;
// All draws we store have an implicit draw token. This is the draw token for the first draw
// in fDraws.
@ -156,7 +161,6 @@ private:
// Variables that are used to track where we are in lists as ops are executed
SkArenaAllocList<Draw>::Iter fCurrDraw;
int fCurrMesh;
SkArenaAllocList<InlineUpload>::Iter fCurrUpload;
// Used to track the proxies that need to be uninstantiated after we finish a flush

View File

@ -1,56 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPendingProgramElement_DEFINED
#define GrPendingProgramElement_DEFINED
#include "SkRefCnt.h"
#include "GrTypes.h"
/**
* Helper for owning a pending execution on a GrProgramElement. Using this rather than ref allows
* resources that are owned by the program element to be correctly tracked as having pending reads
* and writes rather than refs.
*/
template <typename T> class GrPendingProgramElement : SkNoncopyable {
public:
GrPendingProgramElement() : fObj(nullptr) { }
// Adds a pending execution on obj.
explicit GrPendingProgramElement(T* obj) : fObj(obj) {
if (obj) {
obj->addPendingExecution();
}
}
void reset(T* obj) {
if (obj) {
obj->addPendingExecution();
}
if (fObj) {
fObj->completedExecution();
}
fObj = obj;
}
T* get() const { return fObj; }
operator T*() { return fObj; }
T *operator->() const { return fObj; }
~GrPendingProgramElement() {
if (fObj) {
fObj->completedExecution();
}
}
private:
T* fObj;
typedef SkNoncopyable INHERITED;
};
#endif

View File

@ -12,7 +12,6 @@
#include "GrFragmentProcessor.h"
#include "GrNonAtomicRef.h"
#include "GrPendingIOResource.h"
#include "GrPendingProgramElement.h"
#include "GrProcessorSet.h"
#include "GrProgramDesc.h"
#include "GrRect.h"
@ -76,8 +75,11 @@ public:
* 2) DynamicStateArrays - use this to specify per mesh values for dynamic state.
**/
struct FixedDynamicState {
FixedDynamicState(const SkIRect& scissorRect) : fScissorRect(scissorRect) {}
SkIRect fScissorRect;
explicit FixedDynamicState(const SkIRect& scissorRect) : fScissorRect(scissorRect) {}
FixedDynamicState() = default;
SkIRect fScissorRect = SkIRect::EmptyIRect();
// Must have GrPrimitiveProcessor::numTextureSamplers() entries. Can be null if no samplers.
GrTextureProxy** fPrimitiveProcessorTextures = nullptr;
};
/**

View File

@ -74,33 +74,6 @@ size_t GrPrimitiveProcessor::debugOnly_instanceAttributeOffset(int i) const {
}
#endif
void GrPrimitiveProcessor::addPendingIOs() const {
for (int i = 0; i < fTextureSamplerCnt; ++i) {
this->textureSampler(i).proxyRef()->markPendingIO();
}
}
void GrPrimitiveProcessor::removeRefs() const {
for (int i = 0; i < fTextureSamplerCnt; ++i) {
this->textureSampler(i).proxyRef()->removeRef();
}
}
void GrPrimitiveProcessor::pendingIOComplete() const {
for (int i = 0; i < fTextureSamplerCnt; ++i) {
this->textureSampler(i).proxyRef()->pendingIOComplete();
}
}
bool GrPrimitiveProcessor::instantiate(GrResourceProvider* resourceProvider) const {
for (int i = 0; i < fTextureSamplerCnt; ++i) {
if (!this->textureSampler(i).instantiate(resourceProvider)) {
return false;
}
}
return true;
}
uint32_t
GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords,
int numCoords) const {
@ -122,34 +95,50 @@ GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, tr
///////////////////////////////////////////////////////////////////////////////////////////////////
GrPrimitiveProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
const GrSamplerState& samplerState,
GrShaderFlags visibility) {
this->reset(std::move(proxy), samplerState, visibility);
static inline GrSamplerState::Filter clamp_filter(GrTextureType type,
GrSamplerState::Filter requestedFilter) {
if (GrTextureTypeHasRestrictedSampling(type)) {
return SkTMin(requestedFilter, GrSamplerState::Filter::kBilerp);
}
return requestedFilter;
}
GrPrimitiveProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
GrPixelConfig config,
const GrSamplerState& samplerState,
GrShaderFlags visibility) {
this->reset(textureType, config, samplerState, visibility);
}
GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
GrPixelConfig config,
GrSamplerState::Filter filterMode,
GrSamplerState::WrapMode wrapXAndY,
GrShaderFlags visibility) {
this->reset(std::move(proxy), filterMode, wrapXAndY, visibility);
this->reset(textureType, config, filterMode, wrapXAndY, visibility);
}
void GrPrimitiveProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
GrPixelConfig config,
const GrSamplerState& samplerState,
GrShaderFlags visibility) {
fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
SkASSERT(kUnknown_GrPixelConfig != config);
fSamplerState = samplerState;
fSamplerState.setFilterMode(SkTMin(samplerState.filter(), this->proxy()->highestFilterMode()));
fSamplerState.setFilterMode(clamp_filter(textureType, samplerState.filter()));
fTextureType = textureType;
fConfig = config;
fVisibility = visibility;
}
void GrPrimitiveProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
GrPixelConfig config,
GrSamplerState::Filter filterMode,
GrSamplerState::WrapMode wrapXAndY,
GrShaderFlags visibility) {
fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
filterMode = SkTMin(filterMode, this->proxy()->highestFilterMode());
SkASSERT(kUnknown_GrPixelConfig != config);
filterMode = clamp_filter(textureType, filterMode);
fSamplerState = GrSamplerState(wrapXAndY, filterMode);
fTextureType = textureType;
fConfig = config;
fVisibility = visibility;
}

View File

@ -9,6 +9,7 @@
#define GrPrimitiveProcessor_DEFINED
#include "GrColor.h"
#include "GrNonAtomicRef.h"
#include "GrProcessor.h"
#include "GrProxyRef.h"
#include "GrShaderVar.h"
@ -36,12 +37,15 @@ class GrCoordTransform;
class GrGLSLPrimitiveProcessor;
/*
/**
* GrPrimitiveProcessor defines an interface which all subclasses must implement. All
* GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
* pipelines, and they must provide some notion of equality
*
* TODO: This class does not really need to be ref counted. Instances should be allocated using
* GrOpFlushState's arena and destroyed when the arena is torn down.
*/
class GrPrimitiveProcessor : public GrProcessor, public GrProgramElement {
class GrPrimitiveProcessor : public GrProcessor, public GrNonAtomicRef<GrPrimitiveProcessor> {
public:
class TextureSampler;
@ -136,8 +140,6 @@ public:
virtual float getSampleShading() const { return 0.0; }
bool instantiate(GrResourceProvider*) const;
protected:
void setVertexAttributeCnt(int cnt) {
SkASSERT(cnt >= 0);
@ -164,11 +166,6 @@ protected:
inline static const TextureSampler& IthTextureSampler(int i);
private:
void addPendingIOs() const final;
void removeRefs() const final;
void pendingIOComplete() const final;
void notifyRefCntIsZero() const final {}
virtual const Attribute& onVertexAttribute(int) const = 0;
virtual const Attribute& onInstanceAttribute(int) const = 0;
virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
@ -190,9 +187,9 @@ class GrPrimitiveProcessor::TextureSampler {
public:
TextureSampler() = default;
TextureSampler(sk_sp<GrTextureProxy>, const GrSamplerState&, GrShaderFlags visibility);
TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&, GrShaderFlags visibility);
explicit TextureSampler(sk_sp<GrTextureProxy>,
explicit TextureSampler(GrTextureType, GrPixelConfig,
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
GrShaderFlags visibility = kFragment_GrShaderFlag);
@ -200,36 +197,25 @@ public:
TextureSampler(const TextureSampler&) = delete;
TextureSampler& operator=(const TextureSampler&) = delete;
void reset(sk_sp<GrTextureProxy>, const GrSamplerState&,
void reset(GrTextureType, GrPixelConfig, const GrSamplerState&,
GrShaderFlags visibility = kFragment_GrShaderFlag);
void reset(sk_sp<GrTextureProxy>,
void reset(GrTextureType, GrPixelConfig,
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
GrShaderFlags visibility = kFragment_GrShaderFlag);
bool instantiate(GrResourceProvider* resourceProvider) const {
return SkToBool(fProxyRef.get()->instantiate(resourceProvider));
}
GrTextureType textureType() const { return fTextureType; }
GrPixelConfig config() const { return fConfig; }
// 'peekTexture' should only ever be called after a successful 'instantiate' call
GrTexture* peekTexture() const {
SkASSERT(fProxyRef.get()->peekTexture());
return fProxyRef.get()->peekTexture();
}
GrTextureProxy* proxy() const { return fProxyRef.get(); }
GrShaderFlags visibility() const { return fVisibility; }
const GrSamplerState& samplerState() const { return fSamplerState; }
bool isInitialized() const { return SkToBool(fProxyRef.get()); }
/**
* For internal use by GrPrimitiveProcessor.
*/
const GrTextureProxyRef* proxyRef() const { return &fProxyRef; }
bool isInitialized() const { return fConfig != kUnknown_GrPixelConfig; }
private:
GrTextureProxyRef fProxyRef;
GrSamplerState fSamplerState;
GrTextureType fTextureType = GrTextureType::k2D;
GrPixelConfig fConfig = kUnknown_GrPixelConfig;
GrShaderFlags fVisibility = kNone_GrShaderFlags;
};

View File

@ -12,7 +12,6 @@
#include "GrBuffer.h"
#include "GrColor.h"
#include "GrProcessorUnitTest.h"
#include "GrProgramElement.h"
#include "GrSamplerState.h"
#include "GrShaderVar.h"
#include "GrSurfaceProxyPriv.h"

View File

@ -80,8 +80,7 @@ static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcesso
uint16_t* k16 = reinterpret_cast<uint16_t*>(b->add32n(word32Count));
for (int i = 0; i < numTextureSamplers; ++i) {
const GrPrimitiveProcessor::TextureSampler& sampler = pp.textureSampler(i);
const GrTexture* tex = sampler.peekTexture();
k16[i] = sampler_key(tex->texturePriv().textureType(), tex->config(), caps);
k16[i] = sampler_key(sampler.textureType(), sampler.config(), caps);
}
// zero the last 16 bits if the number of uniforms for samplers is odd.
if (numTextureSamplers & 0x1) {

View File

@ -1,126 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrProgramElement_DEFINED
#define GrProgramElement_DEFINED
#include "../private/SkTArray.h"
#include "SkRefCnt.h"
/**
* Note: We are converting GrProcessor from ref counting to a single owner model using move
* semantics. This class will be removed.
*
* This is used to track "refs" for two separate types GrProcessor ownership. A regular ref is owned
* by any client that may continue to issue draws that use the GrProgramElement. A recorded op or
* GrPipeline uses "pending executions" instead of refs. A pending execution is cleared after the
* draw is executed (or aborted).
*
* While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
* into the state where it has pending executions AND no refs then it converts its ownership of
* its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is
* safe to recycle a resource even though we still have buffered GrOps that read or write to the
* the resource.
*
* To make this work the subclass GrProcessor implements addPendingIOs, removeRefs, and
* pendingIOComplete. addPendingIOs adds pending reads/writes to GrGpuResources owned by the
* processor as appropriate when the processor is recorded in a GrOpList. removeRefs is called when
* the ref count reaches 0 and the GrProcessor is only owned by "pending executions".
* pendingIOComplete occurs if the resource is still owned by a ref but all recorded draws have been
* completed. Whenever pending executions and refs reach zero the processor is deleted.
*
* The GrProcessor may also implement notifyRefCntIsZero in order to change its ownership of child
* processors from ref to pending execution when the processor is first owned exclusively in pending
* execution mode.
*/
class GrProgramElement : public SkNoncopyable {
public:
virtual ~GrProgramElement() {
// fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
// Set to invalid values.
SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
}
void ref() const {
this->validate();
// Once the ref cnt reaches zero it should never be ref'ed again.
SkASSERT(fRefCnt > 0);
++fRefCnt;
this->validate();
}
void unref() const {
this->validate();
--fRefCnt;
if (0 == fRefCnt) {
this->notifyRefCntIsZero();
if (0 == fPendingExecutions) {
delete this;
return;
} else {
this->removeRefs();
}
}
this->validate();
}
void validate() const {
#ifdef SK_DEBUG
SkASSERT(fRefCnt >= 0);
SkASSERT(fPendingExecutions >= 0);
SkASSERT(fRefCnt + fPendingExecutions > 0);
#endif
}
protected:
GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
void addPendingExecution() const {
this->validate();
if (0 == fPendingExecutions) {
this->addPendingIOs();
}
++fPendingExecutions;
this->validate();
}
void completedExecution() const {
this->validate();
--fPendingExecutions;
if (0 == fPendingExecutions) {
if (0 == fRefCnt) {
delete this;
return;
} else {
this->pendingIOComplete();
}
}
this->validate();
}
private:
virtual void addPendingIOs() const = 0;
virtual void removeRefs() const = 0;
virtual void pendingIOComplete() const = 0;
/** This will be called when the ref cnt is zero. The object may or may not have pending
executions. */
virtual void notifyRefCntIsZero() const = 0;
mutable int32_t fRefCnt;
// Count of deferred executions not yet issued to the 3D API.
mutable int32_t fPendingExecutions;
// Only these classes can access addPendingExecution() and completedExecution().
template <typename T> friend class GrPendingProgramElement;
friend class GrProcessorSet;
typedef SkNoncopyable INHERITED;
};
#endif

View File

@ -339,7 +339,7 @@ bool GrRenderTargetOpList::combineIfPossible(const RecordedOp& a, GrOp* b,
} else if (a.fDstProxy.proxy()) {
return false;
}
return a.fOp->combineIfPossible(b, caps);
return a.fOp->combineIfPossible(b, caps) == GrOp::CombineResult::kMerged;
}
uint32_t GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,

View File

@ -64,10 +64,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fMaxFragmentSamplers = 0;
fMaxCombinedSamplers = 0;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
// TODO: Default this to 0 and only enable image multitexturing when a "safe" threshold is
// known for a GPU class.
fDisableImageMultitexturingDstRectAreaThreshold = std::numeric_limits<size_t>::max();
}
void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
@ -123,8 +119,6 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendS32("Max Combined Samplers", fMaxFragmentSamplers);
writer->appendString("Advanced blend equation interaction",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
writer->appendU64("Disable image multitexturing dst area threshold",
fDisableImageMultitexturingDstRectAreaThreshold);
writer->endObject();
}
@ -145,8 +139,5 @@ void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) {
}
#if GR_TEST_UTILS
fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending;
if (options.fDisableImageMultitexturing) {
fDisableImageMultitexturingDstRectAreaThreshold = 0;
}
#endif
}

View File

@ -204,15 +204,6 @@ public:
int maxCombinedSamplers() const { return fMaxCombinedSamplers; }
/**
* In general using multiple texture units for image rendering seems to be a win at smaller
* sizes of dst rects and a loss at larger sizes. Dst rects above this pixel area threshold will
* not use multitexturing.
*/
size_t disableImageMultitexturingDstRectAreaThreshold() const {
return fDisableImageMultitexturingDstRectAreaThreshold;
}
/**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a

View File

@ -117,7 +117,7 @@ GrDrawOp::RequiresDstTexture GrCCDrawPathsOp::finalize(const GrCaps& caps,
return RequiresDstTexture(analysis.requiresDstTexture());
}
bool GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
GrOp::CombineResult GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
GrCCDrawPathsOp* that = op->cast<GrCCDrawPathsOp>();
SkASSERT(fOwningPerOpListPaths);
SkASSERT(fNumDraws);
@ -126,7 +126,7 @@ bool GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
if (fProcessors != that->fProcessors ||
fViewMatrixIfUsingLocalCoords != that->fViewMatrixIfUsingLocalCoords) {
return false;
return CombineResult::kCannotCombine;
}
fDraws.append(std::move(that->fDraws), &fOwningPerOpListPaths->fAllocator);
@ -134,7 +134,7 @@ bool GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
SkDEBUGCODE(fNumDraws += that->fNumDraws);
SkDEBUGCODE(that->fNumDraws = 0);
return true;
return CombineResult::kMerged;
}
void GrCCDrawPathsOp::wasRecorded(GrCCPerOpListPaths* owningPerOpListPaths) {
@ -312,7 +312,7 @@ void GrCCDrawPathsOp::setupResources(GrOnFlushResourceProvider* onFlushRP,
}
}
inline void GrCCDrawPathsOp::recordInstance(const GrTextureProxy* atlasProxy, int instanceIdx) {
inline void GrCCDrawPathsOp::recordInstance(GrTextureProxy* atlasProxy, int instanceIdx) {
if (fInstanceRanges.empty()) {
fInstanceRanges.push_back({atlasProxy, instanceIdx});
return;
@ -347,8 +347,9 @@ void GrCCDrawPathsOp::onExecute(GrOpFlushState* flushState) {
for (const InstanceRange& range : fInstanceRanges) {
SkASSERT(range.fEndInstanceIdx > baseInstance);
GrCCPathProcessor pathProc(flushState->resourceProvider(), sk_ref_sp(range.fAtlasProxy),
fViewMatrixIfUsingLocalCoords);
GrCCPathProcessor pathProc(range.fAtlasProxy, fViewMatrixIfUsingLocalCoords);
GrTextureProxy* atlasProxy = range.fAtlasProxy;
fixedDynamicState.fPrimitiveProcessorTextures = &atlasProxy;
pathProc.drawPaths(flushState, pipeline, &fixedDynamicState, *resources, baseInstance,
range.fEndInstanceIdx, this->bounds());

View File

@ -37,7 +37,7 @@ public:
const char* name() const override { return "GrCCDrawPathsOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override;
bool onCombineIfPossible(GrOp*, const GrCaps&) override;
CombineResult onCombineIfPossible(GrOp*, const GrCaps&) override;
void visitProxies(const VisitProxyFunc& fn) const override { fProcessors.visitProxies(fn); }
void onPrepare(GrOpFlushState*) override {}
@ -80,7 +80,7 @@ private:
const SkIRect& maskDevIBounds, Visibility maskVisibility,
const SkRect& devBounds, GrPaint&&);
void recordInstance(const GrTextureProxy* atlasProxy, int instanceIdx);
void recordInstance(GrTextureProxy* atlasProxy, int instanceIdx);
const SkMatrix fViewMatrixIfUsingLocalCoords;
@ -110,7 +110,7 @@ private:
GrProcessorSet fProcessors;
struct InstanceRange {
const GrTextureProxy* fAtlasProxy;
GrTextureProxy* fAtlasProxy;
int fEndInstanceIdx;
};

View File

@ -79,12 +79,14 @@ sk_sp<const GrBuffer> GrCCPathProcessor::FindIndexBuffer(GrOnFlushResourceProvid
}
}
GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider,
sk_sp<GrTextureProxy> atlas,
GrCCPathProcessor::GrCCPathProcessor(const GrTextureProxy* atlas,
const SkMatrix& viewMatrixIfUsingLocalCoords)
: INHERITED(kGrCCPathProcessor_ClassID)
, fAtlasAccess(std::move(atlas), GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag) {
, fAtlasAccess(atlas->textureType(), atlas->config(), GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag)
, fAtlasSize(atlas->isize())
, fAtlasOrigin(atlas->origin()) {
// TODO: Can we just assert that atlas has GrCCAtlas::kTextureOrigin and remove fAtlasOrigin?
this->setInstanceAttributeCnt(kNumInstanceAttribs);
// Check that instance attributes exactly match Instance struct layout.
SkASSERT(!strcmp(this->instanceAttribute(0).name(), "devbounds"));
@ -98,8 +100,6 @@ GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider,
SkASSERT(this->debugOnly_instanceStride() == sizeof(Instance));
this->setVertexAttributeCnt(1);
fAtlasAccess.instantiate(resourceProvider);
this->setTextureSamplerCnt(1);
if (!viewMatrixIfUsingLocalCoords.invert(&fLocalMatrix)) {
@ -115,8 +115,8 @@ private:
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
FPCoordTransformIter&& transformIter) override {
const GrCCPathProcessor& proc = primProc.cast<GrCCPathProcessor>();
pdman.set2f(fAtlasAdjustUniform, 1.0f / proc.atlas()->width(),
1.0f / proc.atlas()->height());
pdman.set2f(fAtlasAdjustUniform, 1.0f / proc.atlasSize().fWidth,
1.0f / proc.atlasSize().fHeight);
this->setTransformDataHelper(proc.localMatrix(), pdman, &transformIter);
}
@ -210,10 +210,10 @@ void GLSLPathProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
// Convert to atlas coordinates in order to do our texture lookup.
v->codeAppendf("float2 atlascoord = octocoord + float2(%s);",
proc.getInstanceAttrib(InstanceAttribs::kDevToAtlasOffset).name());
if (kTopLeft_GrSurfaceOrigin == proc.atlasProxy()->origin()) {
if (kTopLeft_GrSurfaceOrigin == proc.atlasOrigin()) {
v->codeAppendf("%s.xy = atlascoord * %s;", texcoord.vsOut(), atlasAdjust);
} else {
SkASSERT(kBottomLeft_GrSurfaceOrigin == proc.atlasProxy()->origin());
SkASSERT(kBottomLeft_GrSurfaceOrigin == proc.atlasOrigin());
v->codeAppendf("%s.xy = float2(atlascoord.x * %s.x, 1 - atlascoord.y * %s.y);",
texcoord.vsOut(), atlasAdjust, atlasAdjust);
}

View File

@ -69,12 +69,12 @@ public:
static sk_sp<const GrBuffer> FindVertexBuffer(GrOnFlushResourceProvider*);
static sk_sp<const GrBuffer> FindIndexBuffer(GrOnFlushResourceProvider*);
GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas,
GrCCPathProcessor(const GrTextureProxy* atlas,
const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I());
const char* name() const override { return "GrCCPathProcessor"; }
const GrSurfaceProxy* atlasProxy() const { return fAtlasAccess.proxy(); }
const GrTexture* atlas() const { return fAtlasAccess.peekTexture(); }
const SkISize& atlasSize() const { return fAtlasSize; }
GrSurfaceOrigin atlasOrigin() const { return fAtlasOrigin; }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
const Attribute& getInstanceAttrib(InstanceAttribs attribID) const {
int idx = static_cast<int>(attribID);
@ -96,6 +96,9 @@ private:
const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
const TextureSampler fAtlasAccess;
SkISize fAtlasSize;
GrSurfaceOrigin fAtlasOrigin;
SkMatrix fLocalMatrix;
static constexpr Attribute kInstanceAttribs[kNumInstanceAttribs] = {
{"devbounds", kFloat4_GrVertexAttribType},

View File

@ -27,9 +27,9 @@ public:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps&) override {
CombineResult onCombineIfPossible(GrOp* other, const GrCaps&) override {
SK_ABORT("Only expected one Op per CCPR atlas.");
return true;
return CombineResult::kMerged;
}
void onPrepare(GrOpFlushState*) override {}
@ -65,14 +65,18 @@ public:
void onExecute(GrOpFlushState* flushState) override {
SkASSERT(fStashedAtlasProxy);
GrPipeline::FixedDynamicState dynamicState;
auto atlasProxy = fStashedAtlasProxy.get();
dynamicState.fPrimitiveProcessorTextures = &atlasProxy;
GrPipeline pipeline(flushState->proxy(), GrPipeline::ScissorState::kDisabled,
SkBlendMode::kSrc);
GrCCPathProcessor pathProc(flushState->resourceProvider(), std::move(fStashedAtlasProxy));
pathProc.drawPaths(flushState, pipeline, nullptr, *fResources, fBaseInstance, fEndInstance,
this->bounds());
GrCCPathProcessor pathProc(atlasProxy);
pathProc.drawPaths(flushState, pipeline, &dynamicState, *fResources, fBaseInstance,
fEndInstance, this->bounds());
// Ensure we released the stashed atlas proxy. This allows its underlying texture to be
// reused as the current flush's mainline CCPR atlas if needed.
SkASSERT(!fStashedAtlasProxy);
fStashedAtlasProxy.reset();
}
private:

View File

@ -86,13 +86,12 @@ public:
fColor = btgp.color();
}
SkASSERT(btgp.numTextureSamplers() >= 1);
GrTexture* atlas = btgp.textureSampler(0).peekTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
const SkISize& atlasSize = btgp.atlasSize();
SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
fAtlasSize.set(atlas->width(), atlas->height());
if (fAtlasSize != atlasSize) {
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
fAtlasSize = atlasSize;
}
this->setTransformDataHelper(btgp.localMatrix(), pdman, &transformIter);
}
@ -149,9 +148,13 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color,
this->setVertexAttributeCnt(cnt);
if (numActiveProxies) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numActiveProxies; ++i) {
SkASSERT(proxies[i]);
fTextureSamplers[i].reset(std::move(proxies[i]), params);
SkASSERT(proxies[i]->isize() == fAtlasSize);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
this->setTextureSamplerCnt(numActiveProxies);
}
@ -165,11 +168,16 @@ void GrBitmapTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
const GrSamplerState& params) {
SkASSERT(numActiveProxies <= kMaxTextures);
if (!fTextureSamplers[0].isInitialized()) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numActiveProxies; ++i) {
SkASSERT(proxies[i]);
SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
fTextureSamplers[i].reset(std::move(proxies[i]), params);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
}
this->setTextureSamplerCnt(numActiveProxies);

View File

@ -21,6 +21,7 @@ class GrInvariantOutput;
*/
class GrBitmapTextGeoProc : public GrGeometryProcessor {
public:
static constexpr int kMaxTextures = 4;
static sk_sp<GrGeometryProcessor> Make(GrColor color,
const sk_sp<GrTextureProxy>* proxies,
@ -44,6 +45,7 @@ public:
bool hasVertexColor() const { return fInColor.isInitialized(); }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
bool usesW() const { return fUsesW; }
const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@ -52,8 +54,6 @@ public:
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
private:
static constexpr int kMaxTextures = 4;
GrBitmapTextGeoProc(GrColor, const sk_sp<GrTextureProxy>* proxies, int numProxies,
const GrSamplerState& params, GrMaskFormat format,
const SkMatrix& localMatrix, bool usesW);
@ -64,6 +64,7 @@ private:
GrColor fColor;
SkMatrix fLocalMatrix;
bool fUsesW;
SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
TextureSampler fTextureSamplers[kMaxTextures];
Attribute fInPosition;
Attribute fInColor;

View File

@ -172,15 +172,13 @@ public:
}
#endif
SkASSERT(dfa8gp.numTextureSamplers() >= 1);
GrTexture* atlas = dfa8gp.textureSampler(0).peekTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
const SkISize& atlasSize = dfa8gp.atlasSize();
SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
fAtlasSize.set(atlas->width(), atlas->height());
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
if (fAtlasSize != atlasSize) {
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
fAtlasSize = atlasSize;
}
this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter);
}
@ -234,9 +232,13 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(const sk_sp<GrTexture
}
this->setVertexAttributeCnt(3);
if (numProxies) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
fTextureSamplers[i].reset(std::move(proxies[i]), params);
SkASSERT(proxies[i]->isize() == fAtlasSize);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
this->setTextureSamplerCnt(numProxies);
}
@ -246,10 +248,15 @@ void GrDistanceFieldA8TextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* pr
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
if (!fTextureSamplers[0].isInitialized()) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
fTextureSamplers[i].reset(std::move(proxies[i]), params);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
}
this->setTextureSamplerCnt(numProxies);
@ -460,13 +467,11 @@ public:
pdman.setMatrix3f(fMatrixUniform, matrix);
}
SkASSERT(dfpgp.numTextureSamplers() >= 1);
GrTexture* atlas = dfpgp.textureSampler(0).peekTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
fAtlasSize.set(atlas->width(), atlas->height());
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
const SkISize& atlasSize = dfpgp.atlasSize();
SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
if (fAtlasSize != atlasSize) {
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
fAtlasSize = atlasSize;
}
if (dfpgp.matrix().hasPerspective()) {
@ -515,9 +520,15 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(const SkMatrix& matrix,
SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
this->setVertexAttributeCnt(3);
if (numProxies) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
fTextureSamplers[i].reset(std::move(proxies[i]), params);
SkASSERT(proxies[i]->isize() == fAtlasSize);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
this->setTextureSamplerCnt(numProxies);
}
@ -527,11 +538,16 @@ void GrDistanceFieldPathGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* prox
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
if (!fTextureSamplers[0].isInitialized()) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
fTextureSamplers[i].reset(std::move(proxies[i]), params);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
}
this->setTextureSamplerCnt(numProxies);
@ -773,13 +789,11 @@ public:
fDistanceAdjust = wa;
}
SkASSERT(dflcd.numTextureSamplers() >= 1);
GrTexture* atlas = dflcd.textureSampler(0).peekTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
fAtlasSize.set(atlas->width(), atlas->height());
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
const SkISize& atlasSize = dflcd.atlasSize();
SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
if (fAtlasSize != atlasSize) {
pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
fAtlasSize = atlasSize;
}
this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter);
}
@ -829,9 +843,14 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(const sk_sp<GrTextu
}
this->setVertexAttributeCnt(3);
if (numProxies) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
fTextureSamplers[i].reset(std::move(proxies[i]), params);
SkASSERT(proxies[i]->isize() == fAtlasSize);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
this->setTextureSamplerCnt(numProxies);
}
@ -841,11 +860,16 @@ void GrDistanceFieldLCDTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* p
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
if (!fTextureSamplers[0].isInitialized()) {
fAtlasSize = proxies[0]->isize();
}
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
fTextureSamplers[i].reset(std::move(proxies[i]), params);
fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
}
}
this->setTextureSamplerCnt(numProxies);

View File

@ -53,6 +53,8 @@ enum GrDistanceFieldEffectFlags {
*/
class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor {
public:
static constexpr int kMaxTextures = 4;
/** The local matrix should be identity if local coords are not required by the GrPipeline. */
#ifdef SK_GAMMA_APPLY_TO_A8
static sk_sp<GrGeometryProcessor> Make(const sk_sp<GrTextureProxy>* proxies,
@ -84,6 +86,7 @@ public:
float getDistanceAdjust() const { return fDistanceAdjust; }
#endif
uint32_t getFlags() const { return fFlags; }
const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>* proxies, int numProxies, const GrSamplerState&);
@ -106,9 +109,8 @@ private:
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
static constexpr int kMaxTextures = 4;
TextureSampler fTextureSamplers[kMaxTextures];
SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
SkMatrix fLocalMatrix;
Attribute fInPosition;
uint32_t fFlags;
@ -132,6 +134,7 @@ private:
*/
class GrDistanceFieldPathGeoProc : public GrGeometryProcessor {
public:
static constexpr int kMaxTextures = 4;
/** The local matrix should be identity if local coords are not required by the GrPipeline. */
static sk_sp<GrGeometryProcessor> Make(const SkMatrix& matrix,
@ -151,6 +154,7 @@ public:
const Attribute& inTextureCoords() const { return kInTextureCoords; }
const SkMatrix& matrix() const { return fMatrix; }
uint32_t getFlags() const { return fFlags; }
const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@ -159,8 +163,6 @@ public:
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
private:
static constexpr int kMaxTextures = 4;
GrDistanceFieldPathGeoProc(const SkMatrix& matrix,
const sk_sp<GrTextureProxy>* proxies,
int numActiveProxies,
@ -169,8 +171,9 @@ private:
const Attribute& onVertexAttribute(int i) const override;
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise
SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise
TextureSampler fTextureSamplers[kMaxTextures];
SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
uint32_t fFlags;
static constexpr Attribute kInPosition = {"inPosition", kFloat2_GrVertexAttribType};
static constexpr Attribute kInColor = {"inColor", kUByte4_norm_GrVertexAttribType};
@ -189,6 +192,8 @@ private:
*/
class GrDistanceFieldLCDTextGeoProc : public GrGeometryProcessor {
public:
static constexpr int kMaxTextures = 4;
struct DistanceAdjust {
SkScalar fR, fG, fB;
static DistanceAdjust Make(SkScalar r, SkScalar g, SkScalar b) {
@ -225,6 +230,7 @@ public:
DistanceAdjust getDistanceAdjust() const { return fDistanceAdjust; }
uint32_t getFlags() const { return fFlags; }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@ -240,9 +246,8 @@ private:
const Attribute& onVertexAttribute(int) const override;
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
static constexpr int kMaxTextures = 4;
TextureSampler fTextureSamplers[kMaxTextures];
SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
const SkMatrix fLocalMatrix;
DistanceAdjust fDistanceAdjust;
Attribute fInPosition;

View File

@ -364,30 +364,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxSamplers);
shaderCaps->fMaxCombinedSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
// This is all *very* approximate.
switch (ctxInfo.vendor()) {
case kNVIDIA_GrGLVendor:
// We've seen a range from 100 x 100 (TegraK1, GTX660) up to 300 x 300 (GTX 1070)
// but it doesn't clearly align with Pascal vs Maxwell vs Kepler.
fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold = 150 * 150;
break;
case kImagination_GrGLVendor:
// Two PowerVR Rogues, Nexus Player and Chromebook Cb5-312T (PowerVR GX6250), show that
// it is always a win to use multitexturing.
if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold =
std::numeric_limits<size_t>::max();
}
break;
case kATI_GrGLVendor:
// So far no AMD GPU shows a performance difference. A tie goes to disabling
// multitexturing for simplicity's sake.
fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold = 0;
break;
default:
break;
}
// SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with
// frequently changing VBOs. We've measured a performance increase using non-VBO vertex
// data for dynamic content on these GPUs. Perhaps we should read the renderer string and

View File

@ -1675,8 +1675,10 @@ void GrGLGpu::flushMinSampleShading(float minSampleShading) {
}
void GrGLGpu::generateMipmapsForProcessorTextures(const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline) {
const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]) {
auto genLevelsIfNeeded = [this](GrTexture* tex, const GrSamplerState& sampler) {
SkASSERT(tex);
if (sampler.filter() == GrSamplerState::Filter::kMipMap &&
tex->texturePriv().mipMapped() == GrMipMapped::kYes &&
tex->texturePriv().mipMapsAreDirty()) {
@ -1686,8 +1688,8 @@ void GrGLGpu::generateMipmapsForProcessorTextures(const GrPrimitiveProcessor& pr
};
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const auto& textureSampler = primProc.textureSampler(i);
genLevelsIfNeeded(textureSampler.peekTexture(), textureSampler.samplerState());
GrTexture* tex = primProcTextures[i]->peekTexture();
genLevelsIfNeeded(tex, primProc.textureSampler(i).samplerState());
}
GrFragmentProcessor::Iter iter(pipeline);
@ -1708,8 +1710,11 @@ bool GrGLGpu::flushGLState(const GrPrimitiveProcessor& primProc,
GrCapsDebugf(this->caps(), "Failed to create program!\n");
return false;
}
this->generateMipmapsForProcessorTextures(primProc, pipeline);
const GrTextureProxy* const* primProcProxies = nullptr;
if (fixedDynamicState) {
primProcProxies = fixedDynamicState->fPrimitiveProcessorTextures;
}
this->generateMipmapsForProcessorTextures(primProc, pipeline, primProcProxies);
GrXferProcessor::BlendInfo blendInfo;
pipeline.getXferProcessor().getBlendInfo(&blendInfo);
@ -1726,7 +1731,7 @@ bool GrGLGpu::flushGLState(const GrPrimitiveProcessor& primProc,
this->flushBlend(blendInfo, swizzle);
}
fHWProgram->setData(primProc, pipeline);
fHWProgram->updateUniformsAndTextureBindings(primProc, pipeline, primProcProxies);
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.renderTarget());
GrStencilSettings stencil;

View File

@ -247,7 +247,9 @@ private:
void setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]);
void generateMipmapsForProcessorTextures(const GrPrimitiveProcessor&, const GrPipeline&);
void generateMipmapsForProcessorTextures(
const GrPrimitiveProcessor&, const GrPipeline&,
const GrTextureProxy* const primitiveProcessorTextures[]);
// Flushes state from GrPipeline to GL. Returns false if the state couldn't be set.
// willDrawPoints must be true if point primitives will be rendered after setting the GL state.

View File

@ -72,7 +72,10 @@ void GrGLProgram::abandon() {
///////////////////////////////////////////////////////////////////////////////
void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) {
void GrGLProgram::updateUniformsAndTextureBindings(const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]) {
SkASSERT(primProcTextures || !primProc.numTextureSamplers());
this->setRenderTargetState(primProc, pipeline.proxy());
// we set the textures, and uniforms for installed processors in a generic way, but subclasses
@ -85,9 +88,8 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline
fPrimitiveProcessor->setData(fProgramDataManager, primProc,
GrFragmentProcessor::CoordTransformIter(pipeline));
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const GrPrimitiveProcessor::TextureSampler& sampler = primProc.textureSampler(i);
fGpu->bindTexture(nextTexSamplerIdx++, sampler.samplerState(),
static_cast<GrGLTexture*>(sampler.peekTexture()));
auto* tex = static_cast<GrGLTexture*>(primProcTextures[i]->peekTexture());
fGpu->bindTexture(nextTexSamplerIdx++, primProc.textureSampler(i).samplerState(), tex);
}
this->setFragmentData(pipeline, &nextTexSamplerIdx);

View File

@ -19,6 +19,7 @@ class GrGLSLXferProcessor;
class GrPipeline;
class GrPrimitiveProcessor;
class GrRenderTargetProxy;
class GrTextureProxy;
/**
* This class manages a GPU program and records per-program information. It also records the vertex
@ -110,12 +111,13 @@ public:
};
/**
* This function uploads uniforms, calls each GrGL*Processor's setData, and retrieves the
* textures that need to be bound on each unit. It is the caller's responsibility to ensure
* the program is bound before calling, and to bind the outgoing textures to their respective
* units upon return. (Each index in the array corresponds to its matching GL texture unit.)
* This function uploads uniforms, calls each GrGLSL*Processor's setData. It binds all fragment
* processor textures. Primitive process textures are also bound here but are passed separately.
*
* It is the caller's responsibility to ensure the program is bound before calling.
*/
void setData(const GrPrimitiveProcessor&, const GrPipeline&);
void updateUniformsAndTextureBindings(const GrPrimitiveProcessor&, const GrPipeline&,
const GrTextureProxy* const primitiveProcessorTextures[]);
int vertexStride() const { return fVertexStride; }
int instanceStride() const { return fInstanceStride; }

View File

@ -33,11 +33,7 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPrimitiveProcessor& primP
const GrPipeline& pipeline,
GrProgramDesc* desc,
GrGLGpu* gpu) {
#ifdef SK_DEBUG
GrResourceProvider* resourceProvider = gpu->getContext()->contextPriv().resourceProvider();
SkASSERT(!pipeline.isBad() && primProc.instantiate(resourceProvider));
#endif
SkASSERT(!pipeline.isBad());
ATRACE_ANDROID_FRAMEWORK("Shader Compile");
GrAutoLocaleSetter als("C");

View File

@ -101,9 +101,8 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
SkString name;
name.printf("TextureSampler_%d", i);
const auto& sampler = proc.textureSampler(i);
GrTextureType textureType = sampler.peekTexture()->texturePriv().textureType();
texSamplers[i] = this->emitSampler(textureType, sampler.peekTexture()->config(),
name.c_str(), sampler.visibility());
texSamplers[i] = this->emitSampler(sampler.textureType(), sampler.config(), name.c_str(),
sampler.visibility());
}
GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,

View File

@ -843,11 +843,11 @@ private:
extract_lines_only_verts(tess, verts, vertexStride, args.fColor, idxs,
fHelper.compatibleWithAlphaAsCoverage());
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
}
@ -928,37 +928,38 @@ private:
SkSTArray<kPreallocDrawCnt, Draw, true> draws;
create_vertices(segments, fanPt, args.fColor, &draws, verts, idxs);
GrMesh mesh(GrPrimitiveType::kTriangles);
GrMesh* meshes = target->allocMeshes(draws.count());
for (int j = 0; j < draws.count(); ++j) {
const Draw& draw = draws[j];
mesh.setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0, draw.fVertexCnt - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(quadProcessor.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
meshes[j].setPrimitiveType(GrPrimitiveType::kTriangles);
meshes[j].setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0,
draw.fVertexCnt - 1, GrPrimitiveRestart::kNo);
meshes[j].setVertexData(vertexBuffer, firstVertex);
firstIndex += draw.fIndexCnt;
firstVertex += draw.fVertexCnt;
}
target->draw(quadProcessor, pipe.fPipeline, pipe.fFixedDynamicState, meshes,
draws.count());
}
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAConvexPathOp* that = t->cast<AAConvexPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fPaths[0].fViewMatrix.cheapEqualTo(that->fPaths[0].fViewMatrix)) {
return false;
return CombineResult::kCannotCombine;
}
if (fLinesOnly != that->fLinesOnly) {
return false;
return CombineResult::kCannotCombine;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct PathData {

View File

@ -265,10 +265,9 @@ private:
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
sk_sp<const GrBuffer> indexBuffer = get_index_buffer(target->resourceProvider());
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices =
helper.init(target, vertexStride, indexBuffer.get(), kVertsPerAAFillRect,
kIndicesPerAAFillRect, fRectCnt);
PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -292,19 +291,19 @@ private:
info = this->next(info);
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAFillRectOp* that = t->cast<AAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
fRectCnt += that->fRectCnt;
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct RectInfo {

View File

@ -835,41 +835,41 @@ private:
typedef SkTArray<int, true> IntArray;
typedef SkTArray<float, true> FloatArray;
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAHairlineOp* that = t->cast<AAHairlineOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) {
return false;
return CombineResult::kCannotCombine;
}
// We go to identity if we don't have perspective
if (this->viewMatrix().hasPerspective() &&
!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
// TODO we can actually combine hairlines if they are the same color in a kind of bulk
// method but we haven't implemented this yet
// TODO investigate going to vertex color and coverage?
if (this->coverage() != that->coverage()) {
return false;
return CombineResult::kCannotCombine;
}
if (this->color() != that->color()) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
GrColor color() const { return fColor; }
@ -975,11 +975,11 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
add_line(&lines[2*i], toSrc, this->coverage(), &verts);
}
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexedPatterned(linesIndexBuffer.get(), kIdxsPerLineSeg, kLineSegNumVertices,
lineCount, kLineSegsNumInIdxBuffer);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(lineGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexedPatterned(linesIndexBuffer.get(), kIdxsPerLineSeg, kLineSegNumVertices,
lineCount, kLineSegsNumInIdxBuffer);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(std::move(lineGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
if (quadCount || conicCount) {
@ -1030,20 +1030,20 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
}
if (quadCount > 0) {
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
quadCount, kQuadsNumInIdxBuffer);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(quadGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
quadCount, kQuadsNumInIdxBuffer);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(std::move(quadGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
firstVertex += quadCount * kQuadNumVertices;
}
if (conicCount > 0) {
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
conicCount, kQuadsNumInIdxBuffer);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(conicGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
conicCount, kQuadsNumInIdxBuffer);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(std::move(conicGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
}
}

View File

@ -210,14 +210,13 @@ public:
}
private:
void draw(Target* target, const GrGeometryProcessor* gp, const GrPipeline* pipeline,
void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState, int vertexCount,
size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
if (vertexCount == 0 || indexCount == 0) {
return;
}
const GrBuffer* vertexBuffer;
GrMesh mesh(GrPrimitiveType::kTriangles);
int firstVertex;
void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
&firstVertex);
@ -235,10 +234,11 @@ private:
return;
}
memcpy(idxs, indices, indexCount * sizeof(uint16_t));
mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(gp, pipeline, fixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
}
void onPrepareDraws(Target* target) override {
@ -279,7 +279,7 @@ private:
if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
// if we added the current instance, we would overflow the indices we can store in a
// uint16_t. Draw what we've got so far and reset.
this->draw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
this->draw(target, gp, pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
vertexStride, vertices, indexCount, indices);
vertexCount = 0;
indexCount = 0;
@ -311,22 +311,22 @@ private:
indexCount += currentIndices;
}
if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
this->draw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
this->draw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
vertexStride, vertices, indexCount, indices);
}
sk_free(vertices);
sk_free(indices);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }

View File

@ -227,7 +227,7 @@ private:
const SkMatrix& viewMatrix() const { return fViewMatrix; }
bool miterStroke() const { return fMiterStroke; }
bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
void generateAAStrokeRectGeometry(void* vertices,
size_t offset,
@ -282,11 +282,11 @@ void AAStrokeRectOp::onPrepareDraws(Target* target) {
int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt;
int instanceCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = GetIndexBuffer(target->resourceProvider(), this->miterStroke());
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices =
helper.init(target, vertexStride, indexBuffer.get(),
verticesPerInstance, indicesPerInstance, instanceCount);
sk_sp<const GrBuffer> indexBuffer =
GetIndexBuffer(target->resourceProvider(), this->miterStroke());
PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
verticesPerInstance, indicesPerInstance, instanceCount);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -308,7 +308,7 @@ void AAStrokeRectOp::onPrepareDraws(Target* target) {
fHelper.compatibleWithAlphaAsCoverage());
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
sk_sp<const GrBuffer> AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider,
@ -405,27 +405,27 @@ sk_sp<const GrBuffer> AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourc
}
}
bool AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrOp::CombineResult AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
AAStrokeRectOp* that = t->cast<AAStrokeRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
// TODO combine across miterstroke changes
if (this->miterStroke() != that->miterStroke()) {
return false;
return CombineResult::kCannotCombine;
}
// We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
// local coords then we won't be able to combine. TODO: Upload local coords as an attribute.
if (fHelper.usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
static void setup_scale(int* scale, SkScalar inset) {

View File

@ -295,9 +295,16 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
}
SkASSERT(proxies[0]);
static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures;
GR_STATIC_ASSERT(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
GR_STATIC_ASSERT(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
static const uint32_t kPipelineFlags = 0;
auto pipe = target->makePipeline(kPipelineFlags, std::move(fProcessors),
target->detachAppliedClip());
target->detachAppliedClip(), kMaxTextures);
for (unsigned i = 0; i < numActiveProxies; ++i) {
pipe.fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
}
FlushInfo flushInfo;
flushInfo.fPipeline = pipe.fPipeline;
@ -400,6 +407,9 @@ void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) co
if (gp->numTextureSamplers() != (int) numActiveProxies) {
// During preparation the number of atlas pages has increased.
// Update the proxies used in the GP to match.
for (unsigned i = gp->numTextureSamplers(); i < numActiveProxies; ++i) {
flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
}
if (this->usesDistanceFields()) {
if (this->isLCD()) {
reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
@ -415,62 +425,60 @@ void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) co
samplerState);
}
}
GrMesh mesh(GrPrimitiveType::kTriangles);
int maxGlyphsPerDraw =
static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline,
flushInfo->fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
mesh->setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
target->draw(flushInfo->fGeometryProcessor, flushInfo->fPipeline, flushInfo->fFixedDynamicState,
mesh);
flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
flushInfo->fGlyphsToFlush = 0;
}
bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrOp::CombineResult GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
if (fProcessors != that->fProcessors) {
return false;
return CombineResult::kCannotCombine;
}
if (!fCanCombineOnTouchOrOverlap && GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fMaskType != that->fMaskType) {
return false;
return CombineResult::kCannotCombine;
}
const SkMatrix& thisFirstMatrix = fGeoData[0].fViewMatrix;
const SkMatrix& thatFirstMatrix = that->fGeoData[0].fViewMatrix;
if (this->usesLocalCoords() && !thisFirstMatrix.cheapEqualTo(thatFirstMatrix)) {
return false;
return CombineResult::kCannotCombine;
}
if (fNeedsGlyphTransform != that->fNeedsGlyphTransform) {
return false;
return CombineResult::kCannotCombine;
}
if (fNeedsGlyphTransform &&
(thisFirstMatrix.hasPerspective() != thatFirstMatrix.hasPerspective())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->usesDistanceFields()) {
if (fDFGPFlags != that->fDFGPFlags) {
return false;
return CombineResult::kCannotCombine;
}
if (fLuminanceColor != that->fLuminanceColor) {
return false;
return CombineResult::kCannotCombine;
}
} else {
if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
return false;
return CombineResult::kCannotCombine;
}
}
// Keep the batch vertex buffer size below 32K so we don't have to create a special one
@ -478,7 +486,7 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
static const int kVertexSize = sizeof(SkPoint) + sizeof(SkColor) + 2 * sizeof(uint16_t);
static const int kMaxGlyphs = 32768 / (kVerticesPerGlyph * kVertexSize);
if (this->fNumGlyphs + that->fNumGlyphs > kMaxGlyphs) {
return false;
return CombineResult::kCannotCombine;
}
fNumGlyphs += that->numGlyphs();
@ -508,7 +516,7 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
fGeoCount = newGeoCount;
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
// TODO trying to figure out why lcd is so whack

View File

@ -107,7 +107,7 @@ private:
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
GrPipeline::FixedDynamicState* fFixedDynamicState;
int fGlyphsToFlush;
int fVertexOffset;
};
@ -149,7 +149,7 @@ private:
bool usesLocalCoords() const { return fUsesLocalCoords; }
int numGlyphs() const { return fNumGlyphs; }
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
sk_sp<GrGeometryProcessor> setupDfProcessor(const sk_sp<GrTextureProxy>* proxies,
unsigned int numActiveProxies) const;

View File

@ -62,23 +62,23 @@ private:
this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
// This could be much more complicated. Currently we look at cases where the new clear
// contains the old clear, or when the new clear is a subset of the old clear and is the
// same color.
GrClearOp* cb = t->cast<GrClearOp>();
if (fClip.windowRectsState() != cb->fClip.windowRectsState()) {
return false;
return CombineResult::kCannotCombine;
}
if (cb->contains(this)) {
fClip = cb->fClip;
this->replaceBounds(*t);
fColor = cb->fColor;
return true;
return CombineResult::kMerged;
} else if (cb->fColor == fColor && this->contains(cb)) {
return true;
return CombineResult::kMerged;
}
return false;
return CombineResult::kCannotCombine;
}
bool contains(const GrClearOp* that) const {

View File

@ -52,8 +52,6 @@ private:
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;

View File

@ -53,8 +53,6 @@ private:
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;

View File

@ -625,7 +625,6 @@ private:
return;
}
QuadHelper helper;
size_t vertexStride;
if (fullDash) {
vertexStride =
@ -634,7 +633,8 @@ private:
vertexStride = sizeof(SkPoint);
}
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
void* vertices = helper.init(target, vertexStride, totalRectCount);
QuadHelper helper(target, vertexStride, totalRectCount);
void* vertices = helper.vertices();
if (!vertices) {
return;
}
@ -696,43 +696,43 @@ private:
}
auto pipe = target->makePipeline(pipelineFlags, std::move(fProcessorSet),
target->detachAppliedClip());
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DashOp* that = t->cast<DashOp>();
if (fProcessorSet != that->fProcessorSet) {
return false;
return CombineResult::kCannotCombine;
}
if (fDisallowCombineOnTouchOrOverlap &&
GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->aaMode() != that->aaMode()) {
return false;
return CombineResult::kCannotCombine;
}
if (this->fullDash() != that->fullDash()) {
return false;
return CombineResult::kCannotCombine;
}
if (this->cap() != that->cap()) {
return false;
return CombineResult::kCannotCombine;
}
// TODO vertex color
if (this->color() != that->color()) {
return false;
return CombineResult::kCannotCombine;
}
if (fUsesLocalCoords && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
fLines.push_back_n(that->fLines.count(), that->fLines.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
GrColor color() const { return fColor; }

View File

@ -39,8 +39,6 @@ private:
this->makeFullScreen(proxy);
}
bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;

View File

@ -65,12 +65,12 @@ namespace {
class PathGeoBuilder {
public:
PathGeoBuilder(GrPrimitiveType primitiveType, GrMeshDrawOp::Target* target,
GrGeometryProcessor* geometryProcessor, const GrPipeline* pipeline,
sk_sp<const GrGeometryProcessor> geometryProcessor, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState)
: fMesh(primitiveType)
: fPrimitiveType(primitiveType)
, fTarget(target)
, fVertexStride(sizeof(SkPoint))
, fGeometryProcessor(geometryProcessor)
, fGeometryProcessor(std::move(geometryProcessor))
, fPipeline(pipeline)
, fFixedDynamicState(fixedDynamicState)
, fIndexBuffer(nullptr)
@ -200,15 +200,15 @@ private:
* TODO: Cache some of these for better performance, rather than re-computing?
*/
bool isIndexed() const {
return GrPrimitiveType::kLines == fMesh.primitiveType() ||
GrPrimitiveType::kTriangles == fMesh.primitiveType();
return GrPrimitiveType::kLines == fPrimitiveType ||
GrPrimitiveType::kTriangles == fPrimitiveType;
}
bool isHairline() const {
return GrPrimitiveType::kLines == fMesh.primitiveType() ||
GrPrimitiveType::kLineStrip == fMesh.primitiveType();
return GrPrimitiveType::kLines == fPrimitiveType ||
GrPrimitiveType::kLineStrip == fPrimitiveType;
}
int indexScale() const {
switch (fMesh.primitiveType()) {
switch (fPrimitiveType) {
case GrPrimitiveType::kLines:
return 2;
case GrPrimitiveType::kTriangles:
@ -271,14 +271,15 @@ private:
SkASSERT(indexCount <= fIndicesInChunk);
if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
GrMesh* mesh = fTarget->allocMesh(fPrimitiveType);
if (!this->isIndexed()) {
fMesh.setNonIndexedNonInstanced(vertexCount);
mesh->setNonIndexedNonInstanced(vertexCount);
} else {
fMesh.setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1,
mesh->setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1,
GrPrimitiveRestart::kNo);
}
fMesh.setVertexData(fVertexBuffer, fFirstVertex);
fTarget->draw(fGeometryProcessor, fPipeline, fFixedDynamicState, fMesh);
mesh->setVertexData(fVertexBuffer, fFirstVertex);
fTarget->draw(fGeometryProcessor, fPipeline, fFixedDynamicState, mesh);
}
fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
@ -311,10 +312,10 @@ private:
}
}
GrMesh fMesh;
GrPrimitiveType fPrimitiveType;
GrMeshDrawOp::Target* fTarget;
size_t fVertexStride;
GrGeometryProcessor* fGeometryProcessor;
sk_sp<const GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
@ -428,7 +429,7 @@ private:
primitiveType = GrPrimitiveType::kTriangles;
}
auto pipe = fHelper.makePipeline(target);
PathGeoBuilder pathGeoBuilder(primitiveType, target, gp.get(), pipe.fPipeline,
PathGeoBuilder pathGeoBuilder(primitiveType, target, std::move(gp), pipe.fPipeline,
pipe.fFixedDynamicState);
// fill buffers
@ -438,31 +439,31 @@ private:
}
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DefaultPathOp* that = t->cast<DefaultPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->color() != that->color()) {
return false;
return CombineResult::kCannotCombine;
}
if (this->coverage() != that->coverage()) {
return false;
return CombineResult::kCannotCombine;
}
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->isHairline() != that->isHairline()) {
return false;
return CombineResult::kCannotCombine;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
GrColor color() const { return fColor; }

View File

@ -130,9 +130,9 @@ void GrDrawAtlasOp::onPrepareDraws(Target* target) {
sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0);
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
QuadHelper helper;
int numQuads = this->quadCount();
void* verts = helper.init(target, vertexStride, numQuads);
QuadHelper helper(target, vertexStride, numQuads);
void* verts = helper.vertices();
if (!verts) {
SkDebugf("Could not allocate vertices\n");
return;
@ -147,34 +147,34 @@ void GrDrawAtlasOp::onPrepareDraws(Target* target) {
vertPtr += allocSize;
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrOp::CombineResult GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrDrawAtlasOp* that = t->cast<GrDrawAtlasOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
// We currently use a uniform viewmatrix for this op.
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->hasColors() != that->hasColors()) {
return false;
return CombineResult::kCannotCombine;
}
if (!this->hasColors() && this->color() != that->color()) {
return false;
return CombineResult::kCannotCombine;
}
fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
fQuadCount += that->quadCount();
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
GrDrawOp::FixedFunctionFlags GrDrawAtlasOp::fixedFunctionFlags() const {

View File

@ -56,7 +56,7 @@ private:
bool hasColors() const { return fHasColors; }
int quadCount() const { return fQuadCount; }
bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
struct Geometry {
GrColor fColor;

View File

@ -93,8 +93,6 @@ private:
this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
void onExecute(GrOpFlushState* state) override;
GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;

View File

@ -261,7 +261,7 @@ void GrDrawVerticesOp::drawVolatile(Target* target) {
indices);
// Draw the vertices.
this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex);
this->drawVertices(target, std::move(gp), vertexBuffer, firstVertex, indexBuffer, firstIndex);
}
void GrDrawVerticesOp::drawNonVolatile(Target* target) {
@ -298,7 +298,7 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
// Draw using the cached buffers if possible.
if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
this->drawVertices(target, std::move(gp), vertexBuffer.get(), 0, indexBuffer.get(), 0);
return;
}
@ -353,7 +353,7 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
// Draw the vertices.
this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
this->drawVertices(target, std::move(gp), vertexBuffer.get(), 0, indexBuffer.get(), 0);
}
void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
@ -465,59 +465,58 @@ void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
}
void GrDrawVerticesOp::drawVertices(Target* target,
GrGeometryProcessor* gp,
sk_sp<const GrGeometryProcessor> gp,
const GrBuffer* vertexBuffer,
int firstVertex,
const GrBuffer* indexBuffer,
int firstIndex) {
GrMesh mesh(this->primitiveType());
GrMesh* mesh = target->allocMesh(this->primitiveType());
if (this->isIndexed()) {
mesh.setIndexed(indexBuffer, fIndexCount,
firstIndex, 0, fVertexCount - 1,
GrPrimitiveRestart::kNo);
mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1,
GrPrimitiveRestart::kNo);
} else {
mesh.setNonIndexedNonInstanced(fVertexCount);
mesh->setNonIndexedNonInstanced(fVertexCount);
}
mesh.setVertexData(vertexBuffer, firstVertex);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrOp::CombineResult GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
// Meshes with bones cannot be combined because different meshes use different bones, so to
// combine them, the matrices would have to be combined, and the bone indices on each vertex
// would change, thus making the vertices uncacheable.
if (this->hasBones() || that->hasBones()) {
return false;
return CombineResult::kCannotCombine;
}
// Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
// then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
// that was saved in its vertex buffer, which is not necessarily there anymore.
if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
return false;
return CombineResult::kCannotCombine;
}
if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
return false;
return CombineResult::kCannotCombine;
}
if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
return false;
return CombineResult::kCannotCombine;
}
if (fColorArrayType != that->fColorArrayType) {
return false;
return CombineResult::kCannotCombine;
}
if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
return false;
return CombineResult::kCannotCombine;
}
// NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
@ -542,7 +541,7 @@ bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
fIndexCount += that->fIndexCount;
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -80,7 +80,7 @@ private:
uint16_t* indices) const;
void drawVertices(Target*,
GrGeometryProcessor*,
sk_sp<const GrGeometryProcessor>,
const GrBuffer* vertexBuffer,
int firstVertex,
const GrBuffer* indexBuffer,
@ -98,7 +98,7 @@ private:
GrPrimitiveType::kPoints == fPrimitiveType;
}
bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
struct Mesh {
GrColor fColor; // Used if this->hasPerVertexColors() is false.

View File

@ -32,10 +32,10 @@ public:
GrColor fColor;
};
static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxy,
static sk_sp<GrGeometryProcessor> Make(const GrTextureProxy* proxy,
sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter) {
return sk_sp<GrGeometryProcessor>(new LatticeGP(std::move(proxy), std::move(csxf), filter));
return sk_sp<GrGeometryProcessor>(new LatticeGP(proxy, std::move(csxf), filter));
}
const char* name() const override { return "LatticeGP"; }
@ -92,10 +92,10 @@ public:
}
private:
LatticeGP(sk_sp<GrTextureProxy> proxy, sk_sp<GrColorSpaceXform> csxf,
LatticeGP(const GrTextureProxy* proxy, sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter)
: INHERITED(kLatticeGP_ClassID), fColorSpaceXform(std::move(csxf)) {
fSampler.reset(std::move(proxy), filter);
fSampler.reset(proxy->textureType(), proxy->config(), filter);
this->setTextureSamplerCnt(1);
this->setVertexAttributeCnt(4);
}
@ -202,7 +202,7 @@ public:
private:
void onPrepareDraws(Target* target) override {
auto gp = LatticeGP::Make(fProxy, fColorSpaceXform, fFilter);
auto gp = LatticeGP::Make(fProxy.get(), fColorSpaceXform, fFilter);
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
@ -223,9 +223,9 @@ private:
}
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices = helper.init(target, kVertexStide, indexBuffer.get(), kVertsPerRect,
kIndicesPerRect, numRects);
PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStide, indexBuffer.get(),
kVertsPerRect, kIndicesPerRect, numRects);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -281,28 +281,29 @@ private:
kVertsPerRect * patch.fIter->numRectsToDraw());
}
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
auto pipe = fHelper.makePipeline(target, 1);
pipe.fFixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy.get();
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAALatticeOp* that = t->cast<NonAALatticeOp>();
if (fProxy != that->fProxy) {
return false;
return CombineResult::kCannotCombine;
}
if (fFilter != that->fFilter) {
return false;
return CombineResult::kCannotCombine;
}
if (GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())) {
return false;
return CombineResult::kCannotCombine;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
fPatches.move_back_n(that->fPatches.count(), that->fPatches.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct Patch {

View File

@ -14,56 +14,68 @@ GrMeshDrawOp::GrMeshDrawOp(uint32_t classID) : INHERITED(classID) {}
void GrMeshDrawOp::onPrepare(GrOpFlushState* state) { this->onPrepareDraws(state); }
void* GrMeshDrawOp::PatternHelper::init(Target* target, size_t vertexStride,
const GrBuffer* indexBuffer, int verticesPerRepetition,
int indicesPerRepetition, int repeatCount) {
SkASSERT(target);
if (!indexBuffer) {
return nullptr;
}
const GrBuffer* vertexBuffer;
int firstVertex;
int vertexCount = verticesPerRepetition * repeatCount;
void* vertices =
target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex);
if (!vertices) {
SkDebugf("Vertices could not be allocated for instanced rendering.");
return nullptr;
}
SkASSERT(vertexBuffer);
size_t ibSize = indexBuffer->gpuMemorySize();
int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition));
fMesh.setIndexedPatterned(indexBuffer, indicesPerRepetition, verticesPerRepetition,
repeatCount, maxRepetitions);
fMesh.setVertexData(vertexBuffer, firstVertex);
return vertices;
}
void GrMeshDrawOp::PatternHelper::recordDraw(
Target* target, const GrGeometryProcessor* gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState) {
target->draw(gp, pipeline, fixedDynamicState, fMesh);
}
void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) {
sk_sp<const GrBuffer> quadIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
if (!quadIndexBuffer) {
SkDebugf("Could not get quad index buffer.");
return nullptr;
}
return this->INHERITED::init(target, vertexStride, quadIndexBuffer.get(), kVerticesPerQuad,
kIndicesPerQuad, quadsToDraw);
}
void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
state->executeDrawsAndUploadsForMeshDrawOp(this->uniqueID(), this->bounds());
}
//////////////////////////////////////////////////////////////////////////////
GrMeshDrawOp::PatternHelper::PatternHelper(Target* target, GrPrimitiveType primitiveType,
size_t vertexStride, const GrBuffer* indexBuffer,
int verticesPerRepetition, int indicesPerRepetition,
int repeatCount) {
this->init(target, primitiveType, vertexStride, indexBuffer, verticesPerRepetition,
indicesPerRepetition, repeatCount);
}
void GrMeshDrawOp::PatternHelper::init(Target* target, GrPrimitiveType primitiveType,
size_t vertexStride, const GrBuffer* indexBuffer,
int verticesPerRepetition, int indicesPerRepetition,
int repeatCount) {
SkASSERT(target);
if (!indexBuffer) {
return;
}
const GrBuffer* vertexBuffer;
int firstVertex;
int vertexCount = verticesPerRepetition * repeatCount;
fVertices = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex);
if (!fVertices) {
SkDebugf("Vertices could not be allocated for patterned rendering.");
return;
}
SkASSERT(vertexBuffer);
size_t ibSize = indexBuffer->gpuMemorySize();
int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition));
fMesh = target->allocMesh(primitiveType);
fMesh->setIndexedPatterned(indexBuffer, indicesPerRepetition, verticesPerRepetition,
repeatCount, maxRepetitions);
fMesh->setVertexData(vertexBuffer, firstVertex);
}
void GrMeshDrawOp::PatternHelper::recordDraw(
Target* target, sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState) const {
target->draw(std::move(gp), pipeline, fixedDynamicState, fMesh);
}
//////////////////////////////////////////////////////////////////////////////
GrMeshDrawOp::QuadHelper::QuadHelper(Target* target, size_t vertexStride, int quadsToDraw) {
sk_sp<const GrBuffer> quadIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
if (!quadIndexBuffer) {
SkDebugf("Could not get quad index buffer.");
return;
}
this->init(target, GrPrimitiveType::kTriangles, vertexStride, quadIndexBuffer.get(),
kVerticesPerQuad, kIndicesPerQuad, quadsToDraw);
}
//////////////////////////////////////////////////////////////////////////////
GrMeshDrawOp::Target::PipelineAndFixedDynamicState GrMeshDrawOp::Target::makePipeline(
uint32_t pipelineFlags, GrProcessorSet&& processorSet, GrAppliedClip&& clip) {
uint32_t pipelineFlags, GrProcessorSet&& processorSet, GrAppliedClip&& clip,
int numPrimProcTextures) {
GrPipeline::InitArgs pipelineArgs;
pipelineArgs.fFlags = pipelineFlags;
pipelineArgs.fProxy = this->proxy();
@ -71,8 +83,12 @@ GrMeshDrawOp::Target::PipelineAndFixedDynamicState GrMeshDrawOp::Target::makePip
pipelineArgs.fCaps = &this->caps();
pipelineArgs.fResourceProvider = this->resourceProvider();
GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
if (clip.scissorState().enabled()) {
if (clip.scissorState().enabled() || numPrimProcTextures) {
fixedDynamicState = this->allocFixedDynamicState(clip.scissorState().rect());
if (numPrimProcTextures) {
fixedDynamicState->fPrimitiveProcessorTextures =
this->allocPrimitiveProcessorTextureArray(numPrimProcTextures);
}
}
return {this->allocPipeline(pipelineArgs, std::move(processorSet), std::move(clip)),
fixedDynamicState};

View File

@ -12,7 +12,6 @@
#include "GrDrawOp.h"
#include "GrGeometryProcessor.h"
#include "GrMesh.h"
#include "GrPendingProgramElement.h"
class GrAtlasManager;
class GrCaps;
@ -34,18 +33,23 @@ protected:
space for the vertices and flushes the draws to the GrMeshDrawOp::Target. */
class PatternHelper {
public:
PatternHelper(GrPrimitiveType primitiveType) : fMesh(primitiveType) {}
/** Returns the allocated storage for the vertices. The caller should populate the vertices
before calling recordDraws(). */
void* init(Target*, size_t vertexStride, const GrBuffer*, int verticesPerRepetition,
int indicesPerRepetition, int repeatCount);
PatternHelper(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
int verticesPerRepetition, int indicesPerRepetition, int repeatCount);
/** Call after init() to issue draws to the GrMeshDrawOp::Target.*/
void recordDraw(Target*, const GrGeometryProcessor*, const GrPipeline*,
const GrPipeline::FixedDynamicState*);
/** Called to issue draws to the GrMeshDrawOp::Target.*/
void recordDraw(Target*, sk_sp<const GrGeometryProcessor>, const GrPipeline*,
const GrPipeline::FixedDynamicState*) const;
void* vertices() const { return fVertices; }
protected:
PatternHelper() = default;
void init(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
int verticesPerRepetition, int indicesPerRepetition, int repeatCount);
private:
GrMesh fMesh;
void* fVertices = nullptr;
GrMesh* fMesh = nullptr;
};
static const int kVerticesPerQuad = 4;
@ -54,13 +58,11 @@ protected:
/** A specialization of InstanceHelper for quad rendering. */
class QuadHelper : private PatternHelper {
public:
QuadHelper() : INHERITED(GrPrimitiveType::kTriangles) {}
/** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure
and on success a pointer to the vertex data that the caller should populate before
calling recordDraws(). */
void* init(Target*, size_t vertexStride, int quadsToDraw);
QuadHelper() = delete;
QuadHelper(Target* target, size_t vertexStride, int quadsToDraw);
using PatternHelper::recordDraw;
using PatternHelper::vertices;
private:
typedef PatternHelper INHERITED;
@ -78,8 +80,19 @@ public:
virtual ~Target() {}
/** Adds a draw of a mesh. */
virtual void draw(const GrGeometryProcessor*, const GrPipeline*,
const GrPipeline::FixedDynamicState*, const GrMesh&) = 0;
virtual void draw(sk_sp<const GrGeometryProcessor>,
const GrPipeline*,
const GrPipeline::FixedDynamicState*,
const GrMesh[],
int meshCount) = 0;
/** Helper for drawing a single GrMesh. */
void draw(sk_sp<const GrGeometryProcessor> gp,
const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState,
const GrMesh* mesh) {
this->draw(std::move(gp), pipeline, fixedDynamicState, mesh, 1);
}
/**
* Makes space for vertex data. The returned pointer is the location where vertex data
@ -132,10 +145,25 @@ public:
return this->pipelineArena()->make<GrPipeline>(std::forward<Args>(args)...);
}
template <typename... Args>
GrPipeline::FixedDynamicState* allocFixedDynamicState(Args&... args) {
return this->pipelineArena()->make<GrPipeline::FixedDynamicState>(
std::forward<Args>(args)...);
GrMesh* allocMesh(GrPrimitiveType primitiveType) {
return this->pipelineArena()->make<GrMesh>(primitiveType);
}
GrMesh* allocMeshes(int n) { return this->pipelineArena()->makeArray<GrMesh>(n); }
GrPipeline::FixedDynamicState* allocFixedDynamicState(const SkIRect& rect,
int numPrimitiveProcessorTextures = 0) {
auto result = this->pipelineArena()->make<GrPipeline::FixedDynamicState>(rect);
if (numPrimitiveProcessorTextures) {
result->fPrimitiveProcessorTextures =
this->allocPrimitiveProcessorTextureArray(numPrimitiveProcessorTextures);
}
return result;
}
GrTextureProxy** allocPrimitiveProcessorTextureArray(int n) {
SkASSERT(n > 0);
return this->pipelineArena()->makeArrayDefault<GrTextureProxy*>(n);
}
// Once we have C++17 structured bindings make this just be a tuple because then we can do:
@ -144,7 +172,7 @@ public:
// std::tie(flushInfo.fPipeline, flushInfo.fFixedState) = target->makePipeline(...);
struct PipelineAndFixedDynamicState {
const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
GrPipeline::FixedDynamicState* fFixedDynamicState;
};
/**
@ -152,7 +180,8 @@ public:
* GrAppliedClip and uses a fixed dynamic state.
*/
PipelineAndFixedDynamicState makePipeline(uint32_t pipelineFlags, GrProcessorSet&&,
GrAppliedClip&&);
GrAppliedClip&&,
int numPrimitiveProcessorTextures = 0);
virtual GrRenderTargetProxy* proxy() const = 0;

View File

@ -192,9 +192,9 @@ private:
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices = helper.init(target, kVertexStride, indexBuffer.get(), kVertsPerRect,
kIndicesPerRect, rectCount);
PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
kVertsPerRect, kIndicesPerRect, rectCount);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -207,17 +207,17 @@ private:
fRects[i].fRect, &fRects[i].fLocalQuad);
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct RectInfo {
@ -325,9 +325,9 @@ private:
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
kIndicesPerRect, rectCount);
PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
kVertsPerRect, kIndicesPerRect, rectCount);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -345,29 +345,29 @@ private:
}
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
// We could combine across perspective vm changes if we really wanted to.
if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
return false;
return CombineResult::kCannotCombine;
}
if (fHasLocalRect != that->fHasLocalRect) {
return false;
return CombineResult::kCannotCombine;
}
if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
return false;
return CombineResult::kCannotCombine;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct RectInfo {

View File

@ -188,18 +188,14 @@ private:
vertex[4].set(fRect.fLeft, fRect.fTop);
}
GrMesh mesh(primType);
mesh.setNonIndexedNonInstanced(vertexCount);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(primType);
mesh->setNonIndexedNonInstanced(vertexCount);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps&) override {
// NonAA stroke rects cannot combine right now
// TODO make these combinable.
return false;
}
// TODO: override onCombineIfPossible
Helper fHelper;
GrColor fColor;

View File

@ -75,9 +75,21 @@ public:
// This default implementation assumes the op has no proxies
}
bool combineIfPossible(GrOp* that, const GrCaps& caps) {
enum class CombineResult {
/**
* The op that combineIfPossible was called on now represents its own work plus that of
* the passed op. The passed op should be destroyed without being flushed.
*/
kMerged,
/**
* The ops cannot be combined.
*/
kCannotCombine
};
CombineResult combineIfPossible(GrOp* that, const GrCaps& caps) {
if (this->classID() != that->classID()) {
return false;
return CombineResult::kCannotCombine;
}
return this->onCombineIfPossible(that, caps);
@ -211,7 +223,9 @@ protected:
static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); }
private:
virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0;
virtual CombineResult onCombineIfPossible(GrOp*, const GrCaps&) {
return CombineResult::kCannotCombine;
}
virtual void onPrepare(GrOpFlushState*) = 0;
virtual void onExecute(GrOpFlushState*) = 0;

View File

@ -1470,29 +1470,29 @@ private:
vertices += circle_type_to_vert_count(circle.fStroked) * vertexStride;
}
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CircleOp* that = t->cast<CircleOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
return false;
return CombineResult::kCannotCombine;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
return CombineResult::kCannotCombine;
}
// Because we've set up the ops that don't use the planes with noop values
@ -1507,7 +1507,7 @@ private:
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
fAllFill = fAllFill && that->fAllFill;
return true;
return CombineResult::kMerged;
}
struct Circle {
@ -1786,36 +1786,36 @@ private:
vertices += circle_type_to_vert_count(true) * kVertexStride;
}
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
ButtCapDashedCircleOp* that = t->cast<ButtCapDashedCircleOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
return false;
return CombineResult::kCannotCombine;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
return CombineResult::kCannotCombine;
}
fCircles.push_back_n(that->fCircles.count(), that->fCircles.begin());
this->joinBounds(*that);
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
return true;
return CombineResult::kMerged;
}
struct Circle {
@ -1984,10 +1984,9 @@ private:
// Setup geometry processor
sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
QuadHelper helper;
SkASSERT(sizeof(EllipseVertex) == gp->debugOnly_vertexStride());
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
helper.init(target, sizeof(EllipseVertex), fEllipses.count()));
QuadHelper helper(target, sizeof(EllipseVertex), fEllipses.count());
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(helper.vertices());
if (!verts) {
return;
}
@ -2040,28 +2039,28 @@ private:
verts += kVerticesPerQuad;
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
EllipseOp* that = t->cast<EllipseOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fStroked != that->fStroked) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
return CombineResult::kCannotCombine;
}
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct Ellipse {
@ -2219,9 +2218,8 @@ private:
new DIEllipseGeometryProcessor(this->viewMatrix(), this->style()));
SkASSERT(sizeof(DIEllipseVertex) == gp->debugOnly_vertexStride());
QuadHelper helper;
DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
helper.init(target, sizeof(DIEllipseVertex), fEllipses.count()));
QuadHelper helper(target, sizeof(DIEllipseVertex), fEllipses.count());
DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(helper.vertices());
if (!verts) {
return;
}
@ -2274,27 +2272,27 @@ private:
verts += kVerticesPerQuad;
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DIEllipseOp* that = t->cast<DIEllipseOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->style() != that->style()) {
return false;
return CombineResult::kCannotCombine;
}
// TODO rewrite to allow positioning on CPU
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
return false;
return CombineResult::kCannotCombine;
}
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
const SkMatrix& viewMatrix() const { return fEllipses[0].fViewMatrix; }
@ -2725,29 +2723,29 @@ private:
currStartVertex += rrect_type_to_vert_count(rrect.fType);
}
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CircularRRectOp* that = t->cast<CircularRRectOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
return false;
return CombineResult::kCannotCombine;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
return CombineResult::kCannotCombine;
}
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
@ -2755,7 +2753,7 @@ private:
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
fAllFill = fAllFill && that->fAllFill;
return true;
return CombineResult::kMerged;
}
struct RRect {
@ -2927,10 +2925,10 @@ private:
sk_sp<const GrBuffer> indexBuffer = get_rrect_index_buffer(
fStroked ? kStroke_RRectType : kFill_RRectType, target->resourceProvider());
PatternHelper helper(GrPrimitiveType::kTriangles);
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
helper.init(target, sizeof(EllipseVertex), indexBuffer.get(),
kVertsPerStandardRRect, indicesPerInstance, fRRects.count()));
PatternHelper helper(target, GrPrimitiveType::kTriangles, sizeof(EllipseVertex),
indexBuffer.get(), kVertsPerStandardRRect, indicesPerInstance,
fRRects.count());
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(helper.vertices());
if (!verts || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -2997,28 +2995,28 @@ private:
}
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
EllipticalRRectOp* that = t->cast<EllipticalRRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fStroked != that->fStroked) {
return false;
return CombineResult::kCannotCombine;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
return false;
return CombineResult::kCannotCombine;
}
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct RRect {

View File

@ -129,9 +129,9 @@ private:
return;
}
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(GrPrimitiveType::kTriangles);
void* vertices = helper.init(target, kVertexStride, indexBuffer.get(), kVertsPerInstance,
kIndicesPerInstance, numRects);
PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
kVertsPerInstance, kIndicesPerInstance, numRects);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@ -144,22 +144,22 @@ private:
verts += numRectsInRegion * kVertsPerInstance * kVertexStride;
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
RegionOp* that = t->cast<RegionOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (fViewMatrix != that->fViewMatrix) {
return false;
return CombineResult::kCannotCombine;
}
fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
struct RegionInfo {

View File

@ -34,7 +34,6 @@ protected:
sk_sp<GrSemaphore> fSemaphore;
private:
bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
typedef GrOp INHERITED;

View File

@ -627,20 +627,20 @@ private:
auto pipe = target->makePipeline(kPipelineFlags, GrProcessorSet::MakeEmptySet(),
target->detachAppliedClip());
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
this->joinBounds(*that);
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
return true;
return CombineResult::kMerged;
}
SkSTArray<1, Geometry, true> fGeoData;

View File

@ -135,7 +135,8 @@ GrPipeline::InitArgs GrSimpleMeshDrawOpHelper::pipelineInitArgs(
}
auto GrSimpleMeshDrawOpHelper::internalMakePipeline(GrMeshDrawOp::Target* target,
const GrPipeline::InitArgs& args)
const GrPipeline::InitArgs& args,
int numPrimitiveProcessorProxies)
-> PipelineAndFixedDynamicState {
// A caller really should only call this once as the processor set and applied clip get
// moved into the GrPipeline.
@ -143,8 +144,12 @@ auto GrSimpleMeshDrawOpHelper::internalMakePipeline(GrMeshDrawOp::Target* target
SkDEBUGCODE(fMadePipeline = true);
auto clip = target->detachAppliedClip();
GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
if (clip.scissorState().enabled()) {
if (clip.scissorState().enabled() || numPrimitiveProcessorProxies) {
fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect());
if (numPrimitiveProcessorProxies) {
fixedDynamicState->fPrimitiveProcessorTextures =
target->allocPrimitiveProcessorTextureArray(numPrimitiveProcessorProxies);
}
}
if (fProcessors) {
return {target->allocPipeline(args, std::move(*fProcessors), std::move(clip)),
@ -176,11 +181,12 @@ bool GrSimpleMeshDrawOpHelperWithStencil::isCompatible(
fStencilSettings == that.fStencilSettings;
}
auto GrSimpleMeshDrawOpHelperWithStencil::makePipeline(GrMeshDrawOp::Target* target)
auto GrSimpleMeshDrawOpHelperWithStencil::makePipeline(GrMeshDrawOp::Target* target,
int numPrimitiveProcessorTextures)
-> PipelineAndFixedDynamicState {
auto args = INHERITED::pipelineInitArgs(target);
args.fUserStencil = fStencilSettings;
return this->internalMakePipeline(target, args);
return this->internalMakePipeline(target, args, numPrimitiveProcessorTextures);
}
SkString GrSimpleMeshDrawOpHelperWithStencil::dumpInfo() const {

View File

@ -88,8 +88,10 @@ public:
using PipelineAndFixedDynamicState = GrOpFlushState::PipelineAndFixedDynamicState;
/** Makes a pipeline that consumes the processor set and the op's applied clip. */
PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target* target) {
return this->internalMakePipeline(target, this->pipelineInitArgs(target));
PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target* target,
int numPrimitiveProcessorTextures = 0) {
return this->internalMakePipeline(target, this->pipelineInitArgs(target),
numPrimitiveProcessorTextures);
}
struct MakeArgs {
@ -116,7 +118,8 @@ protected:
GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const;
PipelineAndFixedDynamicState internalMakePipeline(GrMeshDrawOp::Target*,
const GrPipeline::InitArgs&);
const GrPipeline::InitArgs&,
int numPrimitiveProcessorTextures);
private:
GrProcessorSet* fProcessors;
@ -162,7 +165,8 @@ public:
bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that, const GrCaps&,
const SkRect& thisBounds, const SkRect& thatBounds) const;
PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target*);
PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target*,
int numPrimitiveProcessorTextures = 0);
SkString dumpInfo() const;

View File

@ -304,7 +304,7 @@ private:
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
GrPipeline::FixedDynamicState* fFixedDynamicState;
int fVertexOffset;
int fInstancesToFlush;
};
@ -312,7 +312,15 @@ private:
void onPrepareDraws(Target* target) override {
int instanceCount = fShapes.count();
auto pipe = fHelper.makePipeline(target);
static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures;
GR_STATIC_ASSERT(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
auto pipe = fHelper.makePipeline(target, kMaxTextures);
int numActiveProxies = fAtlas->numActivePages();
const auto proxies = fAtlas->getProxies();
for (int i = 0; i < numActiveProxies; ++i) {
pipe.fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
}
FlushInfo flushInfo;
flushInfo.fPipeline = pipe.fPipeline;
@ -807,7 +815,12 @@ private:
void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
if (gp->numTextureSamplers() != (int)fAtlas->numActivePages()) {
int numAtlasTextures = SkToInt(fAtlas->numActivePages());
auto proxies = fAtlas->getProxies();
if (gp->numTextureSamplers() != numAtlasTextures) {
for (int i = gp->numTextureSamplers(); i < numAtlasTextures; ++i) {
flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
}
// During preparation the number of atlas pages has increased.
// Update the proxies used in the GP to match.
if (fUsesDistanceField) {
@ -820,14 +833,14 @@ private:
}
if (flushInfo->fInstancesToFlush) {
GrMesh mesh(GrPrimitiveType::kTriangles);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
int maxInstancesPerDraw =
static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerQuad,
kVerticesPerQuad, flushInfo->fInstancesToFlush,
maxInstancesPerDraw);
mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline,
mesh->setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerQuad,
kVerticesPerQuad, flushInfo->fInstancesToFlush,
maxInstancesPerDraw);
mesh->setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
target->draw(flushInfo->fGeometryProcessor, flushInfo->fPipeline,
flushInfo->fFixedDynamicState, mesh);
flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
flushInfo->fInstancesToFlush = 0;
@ -837,41 +850,41 @@ private:
GrColor color() const { return fShapes[0].fColor; }
bool usesDistanceField() const { return fUsesDistanceField; }
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
SmallPathOp* that = t->cast<SmallPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->usesDistanceField() != that->usesDistanceField()) {
return false;
return CombineResult::kCannotCombine;
}
const SkMatrix& thisCtm = this->fShapes[0].fViewMatrix;
const SkMatrix& thatCtm = that->fShapes[0].fViewMatrix;
if (thisCtm.hasPerspective() != thatCtm.hasPerspective()) {
return false;
return CombineResult::kCannotCombine;
}
// We can position on the cpu unless we're in perspective,
// but also need to make sure local matrices are identical
if ((thisCtm.hasPerspective() || fHelper.usesLocalCoords()) &&
!thisCtm.cheapEqualTo(thatCtm)) {
return false;
return CombineResult::kCannotCombine;
}
// Depending on the ctm we may have a different shader for SDF paths
if (this->usesDistanceField()) {
if (thisCtm.isScaleTranslate() != thatCtm.isScaleTranslate() ||
thisCtm.isSimilarity() != thatCtm.isSimilarity()) {
return false;
return CombineResult::kCannotCombine;
}
}
fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin());
this->joinBounds(*that);
return true;
return CombineResult::kMerged;
}
bool fUsesDistanceField;

View File

@ -56,8 +56,6 @@ private:
this->setBounds(path->getBounds(), HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;

View File

@ -237,7 +237,7 @@ private:
return path;
}
void draw(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
SkASSERT(!fAntiAlias);
GrResourceProvider* rp = target->resourceProvider();
bool inverseFill = fShape.inverseFilled();
@ -261,7 +261,7 @@ private:
SkScalar tol = GrPathUtils::kDefaultTolerance;
tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
this->drawVertices(target, std::move(gp), cachedVertexBuffer.get(), 0, actualCount);
return;
}
@ -280,7 +280,7 @@ private:
if (count == 0) {
return;
}
this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
this->drawVertices(target, std::move(gp), allocator.vertexBuffer(), 0, count);
TessInfo info;
info.fTolerance = isLinear ? 0 : tol;
info.fCount = count;
@ -289,7 +289,7 @@ private:
fShape.addGenIDChangeListener(sk_make_sp<PathInvalidator>(key, target->contextUniqueID()));
}
void drawAA(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
void drawAA(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
SkASSERT(fAntiAlias);
SkPath path = getPath();
if (path.isEmpty()) {
@ -306,7 +306,8 @@ private:
if (count == 0) {
return;
}
this->drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex(), count);
this->drawVertices(target, std::move(gp), allocator.vertexBuffer(), allocator.firstVertex(),
count);
}
void onPrepareDraws(Target* target) override {
@ -349,23 +350,22 @@ private:
}
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
if (fAntiAlias) {
this->drawAA(target, gp.get(), vertexStride);
this->drawAA(target, std::move(gp), vertexStride);
} else {
this->draw(target, gp.get(), vertexStride);
this->draw(target, std::move(gp), vertexStride);
}
}
void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuffer* vb,
void drawVertices(Target* target, sk_sp<const GrGeometryProcessor> gp, const GrBuffer* vb,
int firstVertex, int count) {
GrMesh mesh(TESSELLATOR_WIREFRAME ? GrPrimitiveType::kLines : GrPrimitiveType::kTriangles);
mesh.setNonIndexedNonInstanced(count);
mesh.setVertexData(vb, firstVertex);
GrMesh* mesh = target->allocMesh(TESSELLATOR_WIREFRAME ? GrPrimitiveType::kLines
: GrPrimitiveType::kTriangles);
mesh->setNonIndexedNonInstanced(count);
mesh->setVertexData(vb, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
Helper fHelper;
GrColor fColor;
GrShape fShape;

View File

@ -37,8 +37,6 @@
namespace {
enum class MultiTexture : bool { kNo = false, kYes = true };
enum class Domain : bool { kNo = false, kYes = true };
/**
@ -55,79 +53,40 @@ public:
SkPoint fTextureCoords;
};
template <typename Pos, MultiTexture MT> struct OptionalMultiTextureVertex;
template <typename Pos, Domain D> struct OptionalDomainVertex;
template <typename Pos>
struct OptionalMultiTextureVertex<Pos, MultiTexture::kNo> : VertexCommon<Pos> {
static constexpr MultiTexture kMultiTexture = MultiTexture::kNo;
};
template <typename Pos>
struct OptionalMultiTextureVertex<Pos, MultiTexture::kYes> : VertexCommon<Pos> {
static constexpr MultiTexture kMultiTexture = MultiTexture::kYes;
int fTextureIdx;
};
template <typename Pos, MultiTexture MT, Domain D> struct OptionalDomainVertex;
template <typename Pos, MultiTexture MT>
struct OptionalDomainVertex<Pos, MT, Domain::kNo> : OptionalMultiTextureVertex<Pos, MT> {
struct OptionalDomainVertex<Pos, Domain::kNo> : VertexCommon<Pos> {
static constexpr Domain kDomain = Domain::kNo;
};
template <typename Pos, MultiTexture MT>
struct OptionalDomainVertex<Pos, MT, Domain::kYes> : OptionalMultiTextureVertex<Pos, MT> {
template <typename Pos>
struct OptionalDomainVertex<Pos, Domain::kYes> : VertexCommon<Pos> {
static constexpr Domain kDomain = Domain::kYes;
SkRect fTextureDomain;
};
template <typename Pos, MultiTexture MT, Domain D, GrAA> struct OptionalAAVertex;
template <typename Pos, MultiTexture MT, Domain D>
struct OptionalAAVertex<Pos, MT, D, GrAA::kNo> : OptionalDomainVertex<Pos, MT, D> {
template <typename Pos, Domain D, GrAA> struct OptionalAAVertex;
template <typename Pos, Domain D>
struct OptionalAAVertex<Pos, D, GrAA::kNo> : OptionalDomainVertex<Pos, D> {
static constexpr GrAA kAA = GrAA::kNo;
};
template <typename Pos, MultiTexture MT, Domain D>
struct OptionalAAVertex<Pos, MT, D, GrAA::kYes> : OptionalDomainVertex<Pos, MT, D> {
template <typename Pos, Domain D>
struct OptionalAAVertex<Pos, D, GrAA::kYes> : OptionalDomainVertex<Pos, D> {
static constexpr GrAA kAA = GrAA::kYes;
SkPoint3 fEdges[4];
};
template <typename Pos, MultiTexture MT, Domain D, GrAA AA>
using Vertex = OptionalAAVertex<Pos, MT, D, AA>;
template <typename Pos, Domain D, GrAA AA>
using Vertex = OptionalAAVertex<Pos, D, AA>;
// 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
// and could probably use more tuning.
#ifdef SK_BUILD_FOR_ANDROID
static constexpr int kMaxTextures = 4;
#else
static constexpr int kMaxTextures = 8;
#endif
static int SupportsMultitexture(const GrShaderCaps& caps) {
return caps.integerSupport() && caps.maxFragmentSamplers() > 1;
}
static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt,
static sk_sp<GrGeometryProcessor> Make(GrTextureType textureType, GrPixelConfig textureConfig,
const GrSamplerState::Filter filter,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
bool coverageAA,
bool perspective, Domain domain,
const GrSamplerState::Filter filters[],
bool coverageAA, bool perspective, Domain domain,
const GrShaderCaps& caps) {
// We use placement new to avoid always allocating space for kMaxTextures TextureSampler
// instances.
int samplerCnt = NumSamplersToUse(proxyCnt, caps);
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(textureColorSpaceXform),
std::move(paintColorSpaceXform),
coverageAA, perspective, domain, filters, caps));
}
~TextureGeometryProcessor() override {
int cnt = this->numTextureSamplers();
for (int i = 1; i < cnt; ++i) {
fSamplers[i].~TextureSampler();
}
return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
textureType, textureConfig, filter, std::move(textureColorSpaceXform),
std::move(paintColorSpaceXform), coverageAA, perspective, domain, caps));
}
const char* name() const override { return "TextureGeometryProcessor"; }
@ -197,28 +156,10 @@ public:
args.fFragBuilder->codeAppend(
"texCoord = clamp(texCoord, domain.xy, domain.zw);");
}
if (textureGP.numTextureSamplers() > 1) {
// If this changes to float, reconsider Interpolation::kMustBeFlat.
SkASSERT(kInt_GrVertexAttribType == textureGP.fTextureIdx.type());
SkASSERT(args.fShaderCaps->integerSupport());
args.fFragBuilder->codeAppend("int texIdx;");
args.fVaryingHandler->addPassThroughAttribute(textureGP.fTextureIdx, "texIdx",
Interpolation::kMustBeFlat);
args.fFragBuilder->codeAppend("switch (texIdx) {");
for (int i = 0; i < textureGP.numTextureSamplers(); ++i) {
args.fFragBuilder->codeAppendf("case %d: %s = ", i, args.fOutputColor);
args.fFragBuilder->appendTextureLookupAndModulate(
args.fOutputColor, args.fTexSamplers[i], "texCoord",
kFloat2_GrSLType, &fTextureColorSpaceXformHelper);
args.fFragBuilder->codeAppend("; break;");
}
args.fFragBuilder->codeAppend("}");
} else {
args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
args.fFragBuilder->appendTextureLookupAndModulate(
args.fOutputColor, args.fTexSamplers[0], "texCoord",
kFloat2_GrSLType, &fTextureColorSpaceXformHelper);
}
args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
args.fFragBuilder->appendTextureLookupAndModulate(
args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
&fTextureColorSpaceXformHelper);
args.fFragBuilder->codeAppend(";");
if (textureGP.usesCoverageEdgeAA()) {
bool mulByFragCoordW = false;
@ -271,36 +212,16 @@ public:
bool usesCoverageEdgeAA() const { return SkToBool(fAAEdges[0].isInitialized()); }
private:
// This exists to reduce the number of shaders generated. It does some rounding of sampler
// counts.
static int NumSamplersToUse(int numRealProxies, const GrShaderCaps& caps) {
SkASSERT(numRealProxies > 0 && numRealProxies <= kMaxTextures &&
numRealProxies <= caps.maxFragmentSamplers());
if (1 == numRealProxies) {
return 1;
}
if (numRealProxies <= 4) {
return 4;
}
// Round to the next power of 2 and then clamp to kMaxTextures and the max allowed by caps.
return SkTMin(SkNextPow2(numRealProxies), SkTMin(kMaxTextures, caps.maxFragmentSamplers()));
}
TextureGeometryProcessor(sk_sp<GrTextureProxy> proxies[], int proxyCnt, int samplerCnt,
TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
GrSamplerState::Filter filter,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
bool coverageAA, bool perspective, Domain domain,
const GrSamplerState::Filter filters[], const GrShaderCaps& caps)
sk_sp<GrColorSpaceXform> paintColorSpaceXform, bool coverageAA,
bool perspective, Domain domain, const GrShaderCaps& caps)
: INHERITED(kTextureGeometryProcessor_ClassID)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fPaintColorSpaceXform(std::move(paintColorSpaceXform)) {
SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt);
fSamplers[0].reset(std::move(proxies[0]), filters[0]);
for (int i = 1; i < proxyCnt; ++i) {
// This class has one sampler built in, the rest come from memory this processor was
// placement-newed into and so haven't been constructed.
new (&fSamplers[i]) TextureSampler(std::move(proxies[i]), filters[i]);
}
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
, fSampler(textureType, textureConfig, filter) {
this->setTextureSamplerCnt(1);
if (perspective) {
fPositions = {"position", kFloat3_GrVertexAttribType};
@ -311,17 +232,6 @@ private:
fTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType};
int vertexAttributeCnt = 3;
if (samplerCnt > 1) {
// Here we initialize any extra samplers by repeating the last one samplerCnt - proxyCnt
// times.
GrTextureProxy* dupeProxy = fSamplers[proxyCnt - 1].proxy();
for (int i = proxyCnt; i < samplerCnt; ++i) {
new (&fSamplers[i]) TextureSampler(sk_ref_sp(dupeProxy), filters[proxyCnt - 1]);
}
SkASSERT(caps.integerSupport());
fTextureIdx = {"textureIdx", kInt_GrVertexAttribType};
++vertexAttributeCnt;
}
if (domain == Domain::kYes) {
fDomain = {"domain", kFloat4_GrVertexAttribType};
++vertexAttributeCnt;
@ -334,25 +244,23 @@ private:
vertexAttributeCnt += 4;
}
this->setVertexAttributeCnt(vertexAttributeCnt);
this->setTextureSamplerCnt(samplerCnt);
}
const Attribute& onVertexAttribute(int i) const override {
return IthInitializedAttribute(i, fPositions, fColors, fTextureCoords, fTextureIdx, fDomain,
fAAEdges[0], fAAEdges[1], fAAEdges[2], fAAEdges[3]);
return IthInitializedAttribute(i, fPositions, fColors, fTextureCoords, fDomain, fAAEdges[0],
fAAEdges[1], fAAEdges[2], fAAEdges[3]);
}
const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; }
const TextureSampler& onTextureSampler(int) const override { return fSampler; }
Attribute fPositions;
Attribute fColors;
Attribute fTextureCoords;
Attribute fTextureIdx;
Attribute fDomain;
Attribute fAAEdges[4];
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
TextureSampler fSamplers[1];
TextureSampler fSampler;
typedef GrGeometryProcessor INHERITED;
};
@ -527,20 +435,6 @@ private:
}
};
template <typename V, MultiTexture MT = V::kMultiTexture> struct TexIdAssigner;
template <typename V> struct TexIdAssigner<V, MultiTexture::kYes> {
static void Assign(V* vertices, int textureIdx) {
for (int i = 0; i < 4; ++i) {
vertices[i].fTextureIdx = textureIdx;
}
}
};
template <typename V> struct TexIdAssigner<V, MultiTexture::kNo> {
static void Assign(V* vertices, int textureIdx) {}
};
template <typename V, Domain D = V::kDomain> struct DomainAssigner;
template <typename V> struct DomainAssigner<V, Domain::kYes> {
@ -585,7 +479,7 @@ template <typename V> struct DomainAssigner<V, Domain::kNo> {
template <typename V>
static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, GrColor color,
GrSurfaceOrigin origin, GrSamplerState::Filter filter, V* vertices,
SkScalar iw, SkScalar ih, int textureIdx, Domain domain) {
SkScalar iw, SkScalar ih, Domain domain) {
SkRect texRect = {
iw * srcRect.fLeft,
ih * srcRect.fTop,
@ -601,7 +495,6 @@ static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, G
vertices[1].fColor = color;
vertices[2].fColor = color;
vertices[3].fColor = color;
TexIdAssigner<V>::Assign(vertices, textureIdx);
DomainAssigner<V>::Assign(vertices, domain, filter, srcRect, origin, iw, ih);
}
@ -632,42 +525,27 @@ public:
~TextureOp() override {
if (fFinalized) {
auto proxies = this->proxies();
for (int i = 0; i < fProxyCnt; ++i) {
proxies[i]->completedRead();
}
if (fProxyCnt > 1) {
delete[] reinterpret_cast<const char*>(proxies);
}
fProxy->completedRead();
} else {
SkASSERT(1 == fProxyCnt);
fProxy0->unref();
fProxy->unref();
}
}
const char* name() const override { return "TextureOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
auto proxies = this->proxies();
for (int i = 0; i < fProxyCnt; ++i) {
func(proxies[i]);
}
}
void visitProxies(const VisitProxyFunc& func) const override { func(fProxy); }
SkString dumpInfo() const override {
SkString str;
str.appendf("# draws: %d\n", fDraws.count());
auto proxies = this->proxies();
for (int i = 0; i < fProxyCnt; ++i) {
str.appendf("Proxy ID %d: %d, Filter: %d\n", i, proxies[i]->uniqueID().asUInt(),
static_cast<int>(this->filters()[i]));
}
str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(),
static_cast<int>(fFilter));
for (int i = 0; i < fDraws.count(); ++i) {
const Draw& draw = fDraws[i];
str.appendf(
"%d: Color: 0x%08x, ProxyIdx: %d, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
"%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
"Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
i, draw.color(), draw.textureIdx(), draw.srcRect().fLeft, draw.srcRect().fTop,
i, draw.color(), draw.srcRect().fLeft, draw.srcRect().fTop,
draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX,
draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY,
draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX,
@ -679,10 +557,9 @@ public:
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkASSERT(!fFinalized);
SkASSERT(1 == fProxyCnt);
fFinalized = true;
fProxy0->addPendingRead();
fProxy0->unref();
fProxy->addPendingRead();
fProxy->unref();
return RequiresDstTexture::kNo;
}
@ -696,17 +573,6 @@ public:
private:
friend class ::GrOpMemoryPool;
// This is used in a heursitic for choosing a code path. We don't care what happens with
// really large rects, infs, nans, etc.
#if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007
__attribute__((no_sanitize("float-cast-overflow")))
#endif
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, GrAAType aaType,
SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
@ -715,9 +581,8 @@ __attribute__((no_sanitize("float-cast-overflow")))
: INHERITED(ClassID())
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
, fProxy0(proxy.release())
, fFilter0(filter)
, fProxyCnt(1)
, fProxy(proxy.release())
, fFilter(filter)
, fAAType(static_cast<unsigned>(aaType))
, fFinalized(0) {
SkASSERT(aaType != GrAAType::kMixedSamples);
@ -740,46 +605,39 @@ __attribute__((no_sanitize("float-cast-overflow")))
}
}
#endif
const auto& draw = fDraws.emplace_back(srcRect, 0, quad, constraint, color);
const auto& draw = fDraws.emplace_back(srcRect, quad, constraint, color);
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
fDomain = static_cast<bool>(draw.domain());
fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds);
}
template <typename Pos, MultiTexture MT, Domain D, GrAA AA>
void tess(void* v, const float iw[], const float ih[], const GrGeometryProcessor* gp) {
using Vertex = TextureGeometryProcessor::Vertex<Pos, MT, D, AA>;
template <typename Pos, Domain D, GrAA AA>
void tess(void* v, const GrGeometryProcessor* gp) {
using Vertex = TextureGeometryProcessor::Vertex<Pos, D, AA>;
SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex));
auto vertices = static_cast<Vertex*>(v);
auto proxies = this->proxies();
auto filters = this->filters();
auto origin = fProxy->origin();
const auto* texture = fProxy->peekTexture();
float iw = 1.f / texture->width();
float ih = 1.f / texture->height();
for (const auto& draw : fDraws) {
auto textureIdx = draw.textureIdx();
auto origin = proxies[textureIdx]->origin();
tessellate_quad<Vertex>(draw.quad(), draw.srcRect(), draw.color(), origin,
filters[textureIdx], vertices, iw[textureIdx], ih[textureIdx],
textureIdx, draw.domain());
tessellate_quad<Vertex>(draw.quad(), draw.srcRect(), draw.color(), origin, fFilter,
vertices, iw, ih, draw.domain());
vertices += 4;
}
}
void onPrepareDraws(Target* target) override {
sk_sp<GrTextureProxy> proxiesSPs[kMaxTextures];
auto proxies = this->proxies();
auto filters = this->filters();
for (int i = 0; i < fProxyCnt; ++i) {
if (!proxies[i]->instantiate(target->resourceProvider())) {
return;
}
proxiesSPs[i] = sk_ref_sp(proxies[i]);
if (!fProxy->instantiate(target->resourceProvider())) {
return;
}
Domain domain = fDomain ? Domain::kYes : Domain::kNo;
bool coverageAA = GrAAType::kCoverage == this->aaType();
sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
proxiesSPs, fProxyCnt, std::move(fTextureColorSpaceXform),
std::move(fPaintColorSpaceXform), coverageAA, fPerspective,
domain, filters, *target->caps().shaderCaps());
fProxy->textureType(), fProxy->config(), fFilter,
std::move(fTextureColorSpaceXform), std::move(fPaintColorSpaceXform), coverageAA,
fPerspective, domain, *target->caps().shaderCaps());
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
@ -790,43 +648,34 @@ __attribute__((no_sanitize("float-cast-overflow")))
}
auto clip = target->detachAppliedClip();
const auto* fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect());
auto* fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1);
fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy;
const auto* pipeline =
target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
using TessFn =
decltype(&TextureOp::tess<SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kNo>);
#define TESS_FN_AND_VERTEX_SIZE(Point, MT, Domain, AA) \
{ \
&TextureOp::tess<Point, MT, Domain, AA>, \
sizeof(TextureGeometryProcessor::Vertex<Point, MT, Domain, AA>) \
using TessFn = decltype(&TextureOp::tess<SkPoint, Domain::kNo, GrAA::kNo>);
#define TESS_FN_AND_VERTEX_SIZE(Point, Domain, AA) \
{ \
&TextureOp::tess<Point, Domain, AA>, \
sizeof(TextureGeometryProcessor::Vertex<Point, Domain, AA>) \
}
static constexpr struct {
TessFn fTessFn;
size_t fVertexSize;
} kTessFnsAndVertexSizes[] = {
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kYes, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kYes, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kYes, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kYes, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kYes),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kNo),
TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kYes),
};
#undef TESS_FN_AND_VERTEX_SIZE
int tessFnIdx = 0;
tessFnIdx |= coverageAA ? 0x1 : 0x0;
tessFnIdx |= fDomain ? 0x2 : 0x0;
tessFnIdx |= (fProxyCnt > 1) ? 0x4 : 0x0;
tessFnIdx |= fPerspective ? 0x8 : 0x0;
tessFnIdx |= coverageAA ? 0x1 : 0x0;
tessFnIdx |= fDomain ? 0x2 : 0x0;
tessFnIdx |= fPerspective ? 0x4 : 0x0;
SkASSERT(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize == gp->debugOnly_vertexStride());
@ -839,212 +688,75 @@ __attribute__((no_sanitize("float-cast-overflow")))
return;
}
float iw[kMaxTextures];
float ih[kMaxTextures];
for (int t = 0; t < fProxyCnt; ++t) {
const auto* texture = proxies[t]->peekTexture();
iw[t] = 1.f / texture->width();
ih[t] = 1.f / texture->height();
}
(this->*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, iw, ih, gp.get());
(this->*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get());
GrPrimitiveType primitiveType =
fDraws.count() > 1 ? GrPrimitiveType::kTriangles : GrPrimitiveType::kTriangleStrip;
GrMesh mesh(primitiveType);
GrMesh* mesh = target->allocMesh(primitiveType);
if (fDraws.count() > 1) {
sk_sp<const GrBuffer> ibuffer = target->resourceProvider()->refQuadIndexBuffer();
if (!ibuffer) {
SkDebugf("Could not allocate quad indices\n");
return;
}
mesh.setIndexedPatterned(ibuffer.get(), 6, 4, fDraws.count(),
GrResourceProvider::QuadCountOfQuadBuffer());
mesh->setIndexedPatterned(ibuffer.get(), 6, 4, fDraws.count(),
GrResourceProvider::QuadCountOfQuadBuffer());
} else {
mesh.setNonIndexedNonInstanced(4);
mesh->setNonIndexedNonInstanced(4);
}
mesh.setVertexData(vbuffer, vstart);
target->draw(gp.get(), pipeline, fixedDynamicState, mesh);
mesh->setVertexData(vbuffer, vstart);
target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
}
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override {
const auto* that = t->cast<TextureOp>();
const auto& shaderCaps = *caps.shaderCaps();
if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(),
that->fTextureColorSpaceXform.get())) {
return false;
return CombineResult::kCannotCombine;
}
if (!GrColorSpaceXform::Equals(fPaintColorSpaceXform.get(),
that->fPaintColorSpaceXform.get())) {
return false;
return CombineResult::kCannotCombine;
}
if (this->aaType() != that->aaType()) {
return false;
return CombineResult::kCannotCombine;
}
// 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) &&
!fTextureColorSpaceXform &&
fMaxApproxDstPixelArea <= shaderCaps.disableImageMultitexturingDstRectAreaThreshold() &&
that->fMaxApproxDstPixelArea <=
shaderCaps.disableImageMultitexturingDstRectAreaThreshold()) {
int map[kMaxTextures];
int numNewProxies = this->mergeProxies(that, map, shaderCaps);
if (numNewProxies < 0) {
return false;
}
if (1 == fProxyCnt && numNewProxies) {
void* mem = new char[(sizeof(GrSamplerState::Filter) + sizeof(GrTextureProxy*)) *
kMaxTextures];
auto proxies = reinterpret_cast<GrTextureProxy**>(mem);
auto filters = reinterpret_cast<GrSamplerState::Filter*>(proxies + kMaxTextures);
proxies[0] = fProxy0;
filters[0] = fFilter0;
fProxyArray = proxies;
}
fProxyCnt += numNewProxies;
auto thisProxies = fProxyArray;
auto thatProxies = that->proxies();
auto thatFilters = that->filters();
auto thisFilters = reinterpret_cast<GrSamplerState::Filter*>(thisProxies +
kMaxTextures);
for (int i = 0; i < that->fProxyCnt; ++i) {
if (map[i] < 0) {
thatProxies[i]->addPendingRead();
thisProxies[-map[i]] = thatProxies[i];
thisFilters[-map[i]] = thatFilters[i];
map[i] = -map[i];
}
}
int firstNewDraw = fDraws.count();
fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
for (int i = firstNewDraw; i < fDraws.count(); ++i) {
fDraws[i].setTextureIdx(map[fDraws[i].textureIdx()]);
}
} else {
// We can get here when one of the ops is already multitextured but the other cannot
// be because of the dst rect size.
if (fProxyCnt > 1 || that->fProxyCnt > 1) {
return false;
}
if (fProxy0->uniqueID() != that->fProxy0->uniqueID() || fFilter0 != that->fFilter0) {
return false;
}
fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
if (fProxy->uniqueID() != that->fProxy->uniqueID() || fFilter != that->fFilter) {
return CombineResult::kCannotCombine;
}
fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
this->joinBounds(*that);
fMaxApproxDstPixelArea = SkTMax(that->fMaxApproxDstPixelArea, fMaxApproxDstPixelArea);
fPerspective |= that->fPerspective;
fDomain |= that->fDomain;
return true;
}
/**
* Determines a mapping of indices from that's proxy array to this's proxy array. A negative map
* value means that's proxy should be added to this's proxy array at the absolute value of
* the map entry. If it is determined that the ops shouldn't combine their proxies then a
* negative value is returned. Otherwise, return value indicates the number of proxies that have
* to be added to this op or, equivalently, the number of negative entries in map.
*/
int mergeProxies(const TextureOp* that, int map[kMaxTextures], const GrShaderCaps& caps) const {
std::fill_n(map, kMaxTextures, -kMaxTextures);
int sharedProxyCnt = 0;
auto thisProxies = this->proxies();
auto thisFilters = this->filters();
auto thatProxies = that->proxies();
auto thatFilters = that->filters();
for (int i = 0; i < fProxyCnt; ++i) {
for (int j = 0; j < that->fProxyCnt; ++j) {
if (thisProxies[i]->uniqueID() == thatProxies[j]->uniqueID()) {
if (thisFilters[i] != thatFilters[j]) {
// In GL we don't currently support using the same texture with different
// samplers. If we added support for sampler objects and a cap bit to know
// it's ok to use different filter modes then we could support this.
// Otherwise, we could also only allow a single filter mode for each op
// instance.
return -1;
}
map[j] = i;
++sharedProxyCnt;
break;
}
}
}
int actualMaxTextures = SkTMin(caps.maxFragmentSamplers(), kMaxTextures);
int newProxyCnt = that->fProxyCnt - sharedProxyCnt;
if (newProxyCnt + fProxyCnt > actualMaxTextures) {
return -1;
}
GrPixelConfig config = thisProxies[0]->config();
int nextSlot = fProxyCnt;
for (int j = 0; j < that->fProxyCnt; ++j) {
// We want to avoid making many shaders because of different permutations of shader
// based swizzle and sampler types. The approach taken here is to require the configs to
// be the same and to only allow already instantiated proxies that have the most
// common sampler type. Otherwise we don't merge.
if (thatProxies[j]->config() != config) {
return -1;
}
if (GrTexture* tex = thatProxies[j]->peekTexture()) {
if (tex->texturePriv().textureType() != GrTextureType::k2D) {
return -1;
}
}
if (map[j] < 0) {
map[j] = -(nextSlot++);
}
}
return newProxyCnt;
return CombineResult::kMerged;
}
GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
GrTextureProxy* const* proxies() const { return fProxyCnt > 1 ? fProxyArray : &fProxy0; }
const GrSamplerState::Filter* filters() const {
if (fProxyCnt > 1) {
return reinterpret_cast<const GrSamplerState::Filter*>(fProxyArray + kMaxTextures);
}
return &fFilter0;
}
class Draw {
public:
Draw(const SkRect& srcRect, int textureIdx, const GrPerspQuad& quad,
SkCanvas::SrcRectConstraint constraint, GrColor color)
Draw(const SkRect& srcRect, const GrPerspQuad& quad, SkCanvas::SrcRectConstraint constraint,
GrColor color)
: fSrcRect(srcRect)
, fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint)
, fTextureIdx(SkToUInt(textureIdx))
, fQuad(quad)
, fColor(color) {}
, fColor(color)
, fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint) {}
const GrPerspQuad& quad() const { return fQuad; }
int textureIdx() const { return SkToInt(fTextureIdx); }
const SkRect& srcRect() const { return fSrcRect; }
GrColor color() const { return fColor; }
Domain domain() const { return Domain(fHasDomain); }
void setTextureIdx(int i) { fTextureIdx = SkToUInt(i); }
private:
SkRect fSrcRect;
unsigned fHasDomain : 1;
unsigned fTextureIdx : 31;
GrPerspQuad fQuad;
GrColor fColor;
bool fHasDomain;
};
SkSTArray<1, Draw, true> fDraws;
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
// Initially we store a single proxy ptr and a single filter. If we grow to have more than
// one proxy we instead store pointers to dynamically allocated arrays of size kMaxTextures
// followed by kMaxTextures filters.
union {
GrTextureProxy* fProxy0;
GrTextureProxy** fProxyArray;
};
size_t fMaxApproxDstPixelArea;
GrSamplerState::Filter fFilter0;
uint8_t fProxyCnt;
GrTextureProxy* fProxy;
GrSamplerState::Filter fFilter;
unsigned fAAType : 2;
unsigned fPerspective : 1;
unsigned fDomain : 1;
@ -1054,9 +766,6 @@ __attribute__((no_sanitize("float-cast-overflow")))
typedef GrMeshDrawOp INHERITED;
};
constexpr int TextureGeometryProcessor::kMaxTextures;
constexpr int TextureOp::kMaxTextures;
} // anonymous namespace
namespace GrTextureOp {

View File

@ -585,7 +585,11 @@ GrVkPipelineState* GrVkGpuRTCommandBuffer::prepareDrawState(
}
fLastPipelineState = pipelineState;
pipelineState->setData(fGpu, primProc, pipeline);
const GrTextureProxy* const* primProcProxies = nullptr;
if (fixedDynamicState) {
primProcProxies = fixedDynamicState->fPrimitiveProcessorTextures;
}
pipelineState->setData(fGpu, primProc, pipeline, primProcProxies);
pipelineState->bind(fGpu, cbInfo.currentCmdBuf());
@ -643,8 +647,8 @@ void GrVkGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
};
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const GrPrimitiveProcessor::TextureSampler& sampler = primProc.textureSampler(i);
prepareSampledImage(sampler.peekTexture(), sampler.samplerState().filter());
auto texture = fixedDynamicState->fPrimitiveProcessorTextures[i]->peekTexture();
prepareSampledImage(texture, primProc.textureSampler(i).samplerState().filter());
}
GrFragmentProcessor::Iter iter(pipeline);
while (const GrFragmentProcessor* fp = iter.next()) {

View File

@ -167,7 +167,9 @@ void GrVkPipelineState::abandonGPUResources() {
void GrVkPipelineState::setData(GrVkGpu* gpu,
const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline) {
const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]) {
SkASSERT(primProcTextures || !primProc.numTextureSamplers());
// This is here to protect against someone calling setData multiple times in a row without
// freeing the tempData between calls.
this->freeTempResources(gpu);
@ -181,8 +183,8 @@ void GrVkPipelineState::setData(GrVkGpu* gpu,
GrFragmentProcessor::CoordTransformIter(pipeline));
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const auto& sampler = primProc.textureSampler(i);
samplerBindings[currTextureBinding++] = {sampler.samplerState(),
static_cast<GrVkTexture*>(sampler.peekTexture())};
auto texture = static_cast<GrVkTexture*>(primProcTextures[i]->peekTexture());
samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
}
GrFragmentProcessor::Iter iter(pipeline);

View File

@ -56,7 +56,8 @@ public:
~GrVkPipelineState();
void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&,
const GrTextureProxy* const primitiveProcessorTextures[]);
void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);

View File

@ -278,7 +278,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override {
DrawMeshHelper helper(state);

View File

@ -136,7 +136,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override {
GrRenderTargetProxy* proxy = state->drawOpArgs().fProxy;

View File

@ -109,7 +109,6 @@ public:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
LazyProxyTest* const fTest;
@ -324,7 +323,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override {
*fTestExecuteValue = 2;
@ -398,7 +396,6 @@ private:
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override {}

View File

@ -89,8 +89,6 @@ protected:
SkRect fRect;
private:
bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
void onPrepareDraws(Target* target) override {
using namespace GrDefaultGeoProcFactory;
@ -159,12 +157,12 @@ private:
}
}
GrMesh mesh(GrPrimitiveType::kTriangles);
mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
mesh.setVertexData(vertexBuffer, firstVertex);
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
Helper fHelper;

View File

@ -53,8 +53,6 @@ private:
this->setBounds(SkRect::MakeWH(1.f, 1.f), HasAABloat::kNo, IsZeroArea::kNo);
}
bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
void onPrepareDraws(Target* target) override {
class GP : public GrGeometryProcessor {
public:
@ -105,14 +103,14 @@ private:
typedef GrGeometryProcessor INHERITED;
};
sk_sp<GrGeometryProcessor> gp(new GP(fNumAttribs));
QuadHelper helper;
size_t vertexStride = fNumAttribs * GrVertexAttribTypeSize(kFloat2_GrVertexAttribType);
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
QuadHelper helper(target, vertexStride, 1);
SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.vertices());
SkPointPriv::SetRectTriStrip(vertices, 0.f, 0.f, 1.f, 1.f, vertexStride);
auto pipe = target->makePipeline(0, GrProcessorSet::MakeEmptySet(),
target->detachAppliedClip());
helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
int fNumAttribs;

View File

@ -60,8 +60,6 @@ private:
void onPrepareDraws(Target* target) override { return; }
bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
GrProcessorSet fProcessors;
typedef GrMeshDrawOp INHERITED;