Reland "Move GrGeometryProcessor's textures out of classes and into"
This reverts commitfdf05f4ff4
. 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 commitaf87483873
. > > Revert "GrGeometryProcessor derives from GrNonAtomicRef not GrProgramElement." > > This reverts commit607be37e3d
. > > Revert "Store GrMeshDrawOps' meshes in GrOpFlushState's arena." > > This reverts commitb948572c78
. > > Revert "Remove multitexturing support from GrTextureOp." > > This reverts commit986f64c601
. > > Revert "Make result of GrOp::combineIfPossible be an enum." > > This reverts commit641ac7daa8
. > > 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:
parent
0d794288d1
commit
7eae3e04e3
99
bench/CompositingImagesBench.cpp
Normal file
99
bench/CompositingImagesBench.cpp
Normal 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
94
bench/ImageCycleBench.cpp
Normal 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));
|
@ -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));
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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] = {
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -240,6 +240,9 @@ public:
|
||||
SkASSERT(LazyState::kFully != this->lazyInstantiationState());
|
||||
return fHeight;
|
||||
}
|
||||
|
||||
SkISize isize() const { return {fWidth, fHeight}; }
|
||||
|
||||
int worstCaseWidth() const;
|
||||
int worstCaseHeight() const;
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()); }
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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},
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 {}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user