From 7eae3e04e3d388fd548ff5690d122c4ec04a9205 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Tue, 7 Aug 2018 14:02:38 +0000 Subject: [PATCH] Reland "Move GrGeometryProcessor's textures out of classes and into" This reverts commit fdf05f4ff4e96e28a31e210cb471d149d736f528. Reason for revert: Android fixed after removing multitexture support from TextureOp. Original change's description: > Revert "Move GrGeometryProcessor's textures out of classes and into" > > This reverts commit af87483873f0b370b90ebe956301a13cc8662cbe. > > Revert "GrGeometryProcessor derives from GrNonAtomicRef not GrProgramElement." > > This reverts commit 607be37e3d4ddbe2163c200d6e13bcee981f6bf7. > > Revert "Store GrMeshDrawOps' meshes in GrOpFlushState's arena." > > This reverts commit b948572c7862214fe2e1fa6cdfcab4fc7b1666ac. > > Revert "Remove multitexturing support from GrTextureOp." > > This reverts commit 986f64c601f3ed99f84f0c392d1a42e298f6d618. > > Revert "Make result of GrOp::combineIfPossible be an enum." > > This reverts commit 641ac7daa81cbfca06b310803fb1a607d0fc2b32. > > Bug: b/112244393 > Change-Id: I579491a3f2f2f2093f1e2a6141fa1e4cc7b760a4 > Reviewed-on: https://skia-review.googlesource.com/145646 > Reviewed-by: Brian Salomon > Commit-Queue: Brian Salomon 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 Commit-Queue: Brian Salomon --- bench/CompositingImagesBench.cpp | 99 ++++ bench/ImageCycleBench.cpp | 94 ++++ bench/MultitextureImageBench.cpp | 136 ----- bench/VertexColorSpaceBench.cpp | 10 +- gm/beziereffects.cpp | 33 +- gm/clockwise.cpp | 1 - gm/convexpolyeffect.cpp | 8 +- gn/bench.gni | 3 +- gn/gpu.gni | 2 - include/private/GrProxyRef.h | 6 +- include/private/GrSurfaceProxy.h | 3 + samplecode/SampleCCPRGeometry.cpp | 1 - src/atlastext/SkAtlasTextTarget.cpp | 2 +- src/gpu/GrGpuCommandBuffer.cpp | 7 +- src/gpu/GrMesh.h | 6 +- src/gpu/GrOpFlushState.cpp | 35 +- src/gpu/GrOpFlushState.h | 26 +- src/gpu/GrPendingProgramElement.h | 56 -- src/gpu/GrPipeline.h | 8 +- src/gpu/GrPrimitiveProcessor.cpp | 67 +-- src/gpu/GrPrimitiveProcessor.h | 44 +- src/gpu/GrProcessor.h | 1 - src/gpu/GrProgramDesc.cpp | 3 +- src/gpu/GrProgramElement.h | 126 ----- src/gpu/GrRenderTargetOpList.cpp | 2 +- src/gpu/GrShaderCaps.cpp | 9 - src/gpu/GrShaderCaps.h | 9 - src/gpu/ccpr/GrCCDrawPathsOp.cpp | 13 +- src/gpu/ccpr/GrCCDrawPathsOp.h | 6 +- src/gpu/ccpr/GrCCPathProcessor.cpp | 20 +- src/gpu/ccpr/GrCCPathProcessor.h | 9 +- src/gpu/ccpr/GrCCPerFlushResources.cpp | 16 +- src/gpu/effects/GrBitmapTextGeoProc.cpp | 24 +- src/gpu/effects/GrBitmapTextGeoProc.h | 5 +- src/gpu/effects/GrDistanceFieldGeoProc.cpp | 78 ++- src/gpu/effects/GrDistanceFieldGeoProc.h | 19 +- src/gpu/gl/GrGLCaps.cpp | 24 - src/gpu/gl/GrGLGpu.cpp | 17 +- src/gpu/gl/GrGLGpu.h | 4 +- src/gpu/gl/GrGLProgram.cpp | 10 +- src/gpu/gl/GrGLProgram.h | 12 +- src/gpu/gl/builders/GrGLProgramBuilder.cpp | 6 +- src/gpu/glsl/GrGLSLProgramBuilder.cpp | 5 +- src/gpu/ops/GrAAConvexPathRenderer.cpp | 33 +- src/gpu/ops/GrAAFillRectOp.cpp | 15 +- src/gpu/ops/GrAAHairLinePathRenderer.cpp | 46 +- .../ops/GrAALinearizingConvexPathRenderer.cpp | 22 +- src/gpu/ops/GrAAStrokeRectOp.cpp | 24 +- src/gpu/ops/GrAtlasTextOp.cpp | 50 +- src/gpu/ops/GrAtlasTextOp.h | 4 +- src/gpu/ops/GrClearOp.h | 10 +- src/gpu/ops/GrClearStencilClipOp.h | 2 - src/gpu/ops/GrCopySurfaceOp.h | 2 - src/gpu/ops/GrDashOp.cpp | 24 +- src/gpu/ops/GrDebugMarkerOp.h | 2 - src/gpu/ops/GrDefaultPathRenderer.cpp | 45 +- src/gpu/ops/GrDrawAtlasOp.cpp | 18 +- src/gpu/ops/GrDrawAtlasOp.h | 2 +- src/gpu/ops/GrDrawPathOp.h | 2 - src/gpu/ops/GrDrawVerticesOp.cpp | 39 +- src/gpu/ops/GrDrawVerticesOp.h | 4 +- src/gpu/ops/GrLatticeOp.cpp | 33 +- src/gpu/ops/GrMeshDrawOp.cpp | 104 ++-- src/gpu/ops/GrMeshDrawOp.h | 75 ++- src/gpu/ops/GrNonAAFillRectOp.cpp | 34 +- src/gpu/ops/GrNonAAStrokeRectOp.cpp | 14 +- src/gpu/ops/GrOp.h | 20 +- src/gpu/ops/GrOvalOpFactory.cpp | 114 ++-- src/gpu/ops/GrRegionOp.cpp | 16 +- src/gpu/ops/GrSemaphoreOp.h | 1 - src/gpu/ops/GrShadowRRectOp.cpp | 14 +- src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp | 14 +- src/gpu/ops/GrSimpleMeshDrawOpHelper.h | 12 +- src/gpu/ops/GrSmallPathRenderer.cpp | 45 +- src/gpu/ops/GrStencilPathOp.h | 2 - src/gpu/ops/GrTessellatingPathRenderer.cpp | 28 +- src/gpu/ops/GrTextureOp.cpp | 491 ++++-------------- src/gpu/vk/GrVkGpuCommandBuffer.cpp | 10 +- src/gpu/vk/GrVkPipelineState.cpp | 8 +- src/gpu/vk/GrVkPipelineState.h | 3 +- tests/GrMeshTest.cpp | 1 - tests/GrPipelineDynamicStateTest.cpp | 1 - tests/LazyProxyTest.cpp | 3 - tests/OnFlushCallbackTest.cpp | 10 +- tests/PrimitiveProcessorTest.cpp | 8 +- tests/ProcessorTest.cpp | 2 - 86 files changed, 1050 insertions(+), 1422 deletions(-) create mode 100644 bench/CompositingImagesBench.cpp create mode 100644 bench/ImageCycleBench.cpp delete mode 100644 bench/MultitextureImageBench.cpp delete mode 100644 src/gpu/GrPendingProgramElement.h delete mode 100644 src/gpu/GrProgramElement.h diff --git a/bench/CompositingImagesBench.cpp b/bench/CompositingImagesBench.cpp new file mode 100644 index 0000000000..7052bb685e --- /dev/null +++ b/bench/CompositingImagesBench.cpp @@ -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[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[]> 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)); diff --git a/bench/ImageCycleBench.cpp b/bench/ImageCycleBench.cpp new file mode 100644 index 0000000000..e7e00251b8 --- /dev/null +++ b/bench/ImageCycleBench.cpp @@ -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[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[]> fImages; + SkString fName; + int fImageCnt; + int fRepeatCnt; + + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new ImageCycle(5, 10)); diff --git a/bench/MultitextureImageBench.cpp b/bench/MultitextureImageBench.cpp deleted file mode 100644 index edbb4de4e9..0000000000 --- a/bench/MultitextureImageBench.cpp +++ /dev/null @@ -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 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)); diff --git a/bench/VertexColorSpaceBench.cpp b/bench/VertexColorSpaceBench.cpp index 8af1db290f..d2be08f599 100644 --- a/bench/VertexColorSpaceBench.cpp +++ b/bench/VertexColorSpaceBench.cpp @@ -152,8 +152,6 @@ public: private: friend class ::GrOpMemoryPool; - bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; } - void onPrepareDraws(Target* target) override { sk_sp 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; diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp index dbae8693df..016ca9ad40 100644 --- a/gm/beziereffects.cpp +++ b/gm/beziereffects.cpp @@ -40,7 +40,8 @@ public: } protected: - BezierTestOp(sk_sp gp, const SkRect& rect, GrColor color, int32_t classID) + BezierTestOp(sk_sp 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 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 fGeometryProcessor; + sk_sp fGeometryProcessor; GrProcessorSet fProcessorSet; typedef GrMeshDrawOp INHERITED; @@ -76,7 +75,7 @@ public: const char* name() const override { return "BezierCubicTestOp"; } static std::unique_ptr Make(GrContext* context, - sk_sp gp, + sk_sp 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 gp, const SkRect& rect, GrColor color) + BezierCubicTestOp(sk_sp 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(helper.init(target, sizeof(SkPoint), 1)); + QuadHelper helper(target, sizeof(SkPoint), 1); + SkPoint* pts = reinterpret_cast(helper.vertices()); if (!pts) { return; } @@ -261,7 +260,7 @@ public: const char* name() const override { return "BezierConicTestOp"; } static std::unique_ptr Make(GrContext* context, - sk_sp gp, + sk_sp gp, const SkRect& rect, GrColor color, const SkMatrix& klm) { @@ -273,7 +272,7 @@ public: private: friend class ::GrOpMemoryPool; // for ctor - BezierConicTestOp(sk_sp gp, const SkRect& rect, GrColor color, + BezierConicTestOp(sk_sp 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(helper.init(target, sizeof(Vertex), 1)); + QuadHelper helper(target, sizeof(Vertex), 1); + Vertex* verts = reinterpret_cast(helper.vertices()); if (!verts) { return; } @@ -483,7 +482,7 @@ public: const char* name() const override { return "BezierQuadTestOp"; } static std::unique_ptr Make(GrContext* context, - sk_sp gp, + sk_sp gp, const SkRect& rect, GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) { @@ -495,7 +494,7 @@ public: private: friend class ::GrOpMemoryPool; // for ctor - BezierQuadTestOp(sk_sp gp, const SkRect& rect, GrColor color, + BezierQuadTestOp(sk_sp 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(helper.init(target, sizeof(Vertex), 1)); + QuadHelper helper(target, sizeof(Vertex), 1); + Vertex* verts = reinterpret_cast(helper.vertices()); if (!verts) { return; } diff --git a/gm/clockwise.cpp b/gm/clockwise.cpp index 00bc47ecda..7dc38167ba 100644 --- a/gm/clockwise.cpp +++ b/gm/clockwise.cpp @@ -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] = { diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp index 41d53e6241..664a9e7b5f 100644 --- a/gm/convexpolyeffect.cpp +++ b/gm/convexpolyeffect.cpp @@ -87,8 +87,8 @@ private: SkMatrix::I())); SkASSERT(gp->debugOnly_vertexStride() == sizeof(SkPoint)); - QuadHelper helper; - SkPoint* verts = reinterpret_cast(helper.init(target, sizeof(SkPoint), 1)); + QuadHelper helper(target, sizeof(SkPoint), 1); + SkPoint* verts = reinterpret_cast(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; diff --git a/gn/bench.gni b/gn/bench.gni index b3b25611ec..f8dce13ddd 100644 --- a/gn/bench.gni +++ b/gn/bench.gni @@ -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", diff --git a/gn/gpu.gni b/gn/gpu.gni index 399ecf2fd6..6dcb891c59 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -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", diff --git a/include/private/GrProxyRef.h b/include/private/GrProxyRef.h index 7af6ec49d2..9d4419fb31 100644 --- a/include/private/GrProxyRef.h +++ b/include/private/GrProxyRef.h @@ -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. diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h index 5a50314bdf..f18a77d0c1 100644 --- a/include/private/GrSurfaceProxy.h +++ b/include/private/GrSurfaceProxy.h @@ -240,6 +240,9 @@ public: SkASSERT(LazyState::kFully != this->lazyInstantiationState()); return fHeight; } + + SkISize isize() const { return {fWidth, fHeight}; } + int worstCaseWidth() const; int worstCaseHeight() const; /** diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp index 576325337a..a1702f3513 100644 --- a/samplecode/SampleCCPRGeometry.cpp +++ b/samplecode/SampleCCPRGeometry.cpp @@ -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; diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp index 8a382c7233..3d9cf95477 100644 --- a/src/atlastext/SkAtlasTextTarget.cpp +++ b/src/atlastext/SkAtlasTextTarget.cpp @@ -181,7 +181,7 @@ void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptrcombineIfPossible(op.get(), caps)) { + if (other->combineIfPossible(op.get(), caps) == GrOp::CombineResult::kMerged) { fOpMemoryPool->release(std::move(op)); return; } diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp index 42e00f355f..d66f24c741 100644 --- a/src/gpu/GrGpuCommandBuffer.cpp +++ b/src/gpu/GrGpuCommandBuffer.cpp @@ -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(); diff --git a/src/gpu/GrMesh.h b/src/gpu/GrMesh.h index fb7b52516a..e8a3f5cec3 100644 --- a/src/gpu/GrMesh.h +++ b/src/gpu/GrMesh.h @@ -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()); } diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp index 8d8b7bbaf1..6385c9fdce 100644 --- a/src/gpu/GrOpFlushState.cpp +++ b/src/gpu/GrOpFlushState.cpp @@ -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 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; diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h index 66ac34cb87..0a46ed2fd3 100644 --- a/src/gpu/GrOpFlushState.h +++ b/src/gpu/GrOpFlushState.h @@ -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 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 fGeometryProcessor; - const GrPipeline* fPipeline; + ~Draw() { + for (int i = 0; i < fGeometryProcessor->numTextureSamplers(); ++i) { + fFixedDynamicState->fPrimitiveProcessorTextures[i]->completedRead(); + } + } + sk_sp 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 fASAPUploads; SkArenaAllocList fInlineUploads; SkArenaAllocList 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::Iter fCurrDraw; - int fCurrMesh; SkArenaAllocList::Iter fCurrUpload; // Used to track the proxies that need to be uninstantiated after we finish a flush diff --git a/src/gpu/GrPendingProgramElement.h b/src/gpu/GrPendingProgramElement.h deleted file mode 100644 index ab1f437893..0000000000 --- a/src/gpu/GrPendingProgramElement.h +++ /dev/null @@ -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 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 diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h index 24dd9f8ff5..b2f6711cc9 100644 --- a/src/gpu/GrPipeline.h +++ b/src/gpu/GrPipeline.h @@ -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; }; /** diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp index 84db9cafec..6d2b1e9418 100644 --- a/src/gpu/GrPrimitiveProcessor.cpp +++ b/src/gpu/GrPrimitiveProcessor.cpp @@ -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& coords, int numCoords) const { @@ -122,34 +95,50 @@ GrPrimitiveProcessor::getTransformKey(const SkTArray 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 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 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 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; } diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h index ddebd2171f..4becb547cc 100644 --- a/src/gpu/GrPrimitiveProcessor.h +++ b/src/gpu/GrPrimitiveProcessor.h @@ -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 { 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, const GrSamplerState&, GrShaderFlags visibility); + TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&, GrShaderFlags visibility); - explicit TextureSampler(sk_sp, + 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, const GrSamplerState&, + void reset(GrTextureType, GrPixelConfig, const GrSamplerState&, GrShaderFlags visibility = kFragment_GrShaderFlag); - void reset(sk_sp, + 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; }; diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h index 4afb246244..3c6662c5f7 100644 --- a/src/gpu/GrProcessor.h +++ b/src/gpu/GrProcessor.h @@ -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" diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp index e99a947d80..5c10b9f77e 100644 --- a/src/gpu/GrProgramDesc.cpp +++ b/src/gpu/GrProgramDesc.cpp @@ -80,8 +80,7 @@ static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcesso uint16_t* k16 = reinterpret_cast(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) { diff --git a/src/gpu/GrProgramElement.h b/src/gpu/GrProgramElement.h deleted file mode 100644 index ef96738ade..0000000000 --- a/src/gpu/GrProgramElement.h +++ /dev/null @@ -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 friend class GrPendingProgramElement; - friend class GrProcessorSet; - - typedef SkNoncopyable INHERITED; -}; - -#endif diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 569b5fa845..33836a7c04 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -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 op, diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp index 9ab5f90882..d29fe58729 100644 --- a/src/gpu/GrShaderCaps.cpp +++ b/src/gpu/GrShaderCaps.cpp @@ -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::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 } diff --git a/src/gpu/GrShaderCaps.h b/src/gpu/GrShaderCaps.h index a599f1deab..d8422c7c4c 100644 --- a/src/gpu/GrShaderCaps.h +++ b/src/gpu/GrShaderCaps.h @@ -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 diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp index 016756a7f6..aed06721a1 100644 --- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp +++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp @@ -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(); 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()); diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h index 9ef317f759..40d9df43f9 100644 --- a/src/gpu/ccpr/GrCCDrawPathsOp.h +++ b/src/gpu/ccpr/GrCCDrawPathsOp.h @@ -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; }; diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp index ae3cba34ae..4a9a8aa696 100644 --- a/src/gpu/ccpr/GrCCPathProcessor.cpp +++ b/src/gpu/ccpr/GrCCPathProcessor.cpp @@ -79,12 +79,14 @@ sk_sp GrCCPathProcessor::FindIndexBuffer(GrOnFlushResourceProvid } } -GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider, - sk_sp 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(); - 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); } diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h index 752083a1e7..394746b48f 100644 --- a/src/gpu/ccpr/GrCCPathProcessor.h +++ b/src/gpu/ccpr/GrCCPathProcessor.h @@ -69,12 +69,12 @@ public: static sk_sp FindVertexBuffer(GrOnFlushResourceProvider*); static sk_sp FindIndexBuffer(GrOnFlushResourceProvider*); - GrCCPathProcessor(GrResourceProvider*, sk_sp 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(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}, diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp index aed1af7658..2b246c9131 100644 --- a/src/gpu/ccpr/GrCCPerFlushResources.cpp +++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp @@ -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: diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp index 32da45c10f..ee38f43740 100644 --- a/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -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* 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); diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h index 1bc062003e..d2d530ee29 100644 --- a/src/gpu/effects/GrBitmapTextGeoProc.h +++ b/src/gpu/effects/GrBitmapTextGeoProc.h @@ -21,6 +21,7 @@ class GrInvariantOutput; */ class GrBitmapTextGeoProc : public GrGeometryProcessor { public: + static constexpr int kMaxTextures = 4; static sk_sp Make(GrColor color, const sk_sp* 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*, 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* 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; diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp index b9e5681e71..099cc7e0c9 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -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_spsetVertexAttributeCnt(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* 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* 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_spsetVertexAttributeCnt(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* 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); diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h index a0fb9d74e5..fcd98aa0fd 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.h +++ b/src/gpu/effects/GrDistanceFieldGeoProc.h @@ -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 Make(const sk_sp* 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* 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 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*, 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* 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*, 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; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index c0549e98f7..f4960446f1 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -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(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::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 diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index cc858a88ef..7ef043bb1f 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -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(pipeline.renderTarget()); GrStencilSettings stencil; diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 32b2945195..0f1127a58c 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -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. diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index e0eccf2775..9e90642365 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -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(sampler.peekTexture())); + auto* tex = static_cast(primProcTextures[i]->peekTexture()); + fGpu->bindTexture(nextTexSamplerIdx++, primProc.textureSampler(i).samplerState(), tex); } this->setFragmentData(pipeline, &nextTexSamplerIdx); diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index b05b53623d..ca9253c0e3 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -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; } diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index b60088d9c6..ba290ac92c 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -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"); diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index b0cf8169d4..66e333a05a 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -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, diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp index 783cac7c64..e9a612f70f 100644 --- a/src/gpu/ops/GrAAConvexPathRenderer.cpp +++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp @@ -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 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(); 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 { diff --git a/src/gpu/ops/GrAAFillRectOp.cpp b/src/gpu/ops/GrAAFillRectOp.cpp index 592c0b2774..9d66299ef0 100644 --- a/src/gpu/ops/GrAAFillRectOp.cpp +++ b/src/gpu/ops/GrAAFillRectOp.cpp @@ -265,10 +265,9 @@ private: SkASSERT(vertexStride == gp->debugOnly_vertexStride()); sk_sp 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(); 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 { diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp index 05f1fbd684..7cff875245 100644 --- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp +++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp @@ -835,41 +835,41 @@ private: typedef SkTArray IntArray; typedef SkTArray FloatArray; - bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override { AAHairlineOp* that = t->cast(); 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); } } } diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp index 75662d35fe..c40aa71ec5 100644 --- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp +++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp @@ -210,14 +210,13 @@ public: } private: - void draw(Target* target, const GrGeometryProcessor* gp, const GrPipeline* pipeline, + void draw(Target* target, sk_sp 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(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(); 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; } diff --git a/src/gpu/ops/GrAAStrokeRectOp.cpp b/src/gpu/ops/GrAAStrokeRectOp.cpp index 92d1c01a3d..0362946c32 100644 --- a/src/gpu/ops/GrAAStrokeRectOp.cpp +++ b/src/gpu/ops/GrAAStrokeRectOp.cpp @@ -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 indexBuffer = GetIndexBuffer(target->resourceProvider(), this->miterStroke()); - PatternHelper helper(GrPrimitiveType::kTriangles); - void* vertices = - helper.init(target, vertexStride, indexBuffer.get(), - verticesPerInstance, indicesPerInstance, instanceCount); + sk_sp 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 AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider, @@ -405,27 +405,27 @@ sk_sp 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(); 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) { diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index cfd0c45c70..ba39b97b38 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -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(gp)->addNewProxies( @@ -415,62 +425,60 @@ void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) co samplerState); } } - - GrMesh mesh(GrPrimitiveType::kTriangles); int maxGlyphsPerDraw = static_cast(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(); 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 diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index 14f7e953a3..e6e08dcd21 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -107,7 +107,7 @@ private: sk_sp fIndexBuffer; sk_sp 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 setupDfProcessor(const sk_sp* proxies, unsigned int numActiveProxies) const; diff --git a/src/gpu/ops/GrClearOp.h b/src/gpu/ops/GrClearOp.h index 6e76191dff..e62667d569 100644 --- a/src/gpu/ops/GrClearOp.h +++ b/src/gpu/ops/GrClearOp.h @@ -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(); 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 { diff --git a/src/gpu/ops/GrClearStencilClipOp.h b/src/gpu/ops/GrClearStencilClipOp.h index 3e7ad5070f..5861fca300 100644 --- a/src/gpu/ops/GrClearStencilClipOp.h +++ b/src/gpu/ops/GrClearStencilClipOp.h @@ -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; diff --git a/src/gpu/ops/GrCopySurfaceOp.h b/src/gpu/ops/GrCopySurfaceOp.h index bc0e33f4af..b93cbb79c2 100644 --- a/src/gpu/ops/GrCopySurfaceOp.h +++ b/src/gpu/ops/GrCopySurfaceOp.h @@ -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; diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp index 43acc5cebe..075df70dbd 100644 --- a/src/gpu/ops/GrDashOp.cpp +++ b/src/gpu/ops/GrDashOp.cpp @@ -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(); 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; } diff --git a/src/gpu/ops/GrDebugMarkerOp.h b/src/gpu/ops/GrDebugMarkerOp.h index 061f676426..96c5477aba 100644 --- a/src/gpu/ops/GrDebugMarkerOp.h +++ b/src/gpu/ops/GrDebugMarkerOp.h @@ -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; diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp index 07e40f0454..4e038dfc89 100644 --- a/src/gpu/ops/GrDefaultPathRenderer.cpp +++ b/src/gpu/ops/GrDefaultPathRenderer.cpp @@ -65,12 +65,12 @@ namespace { class PathGeoBuilder { public: PathGeoBuilder(GrPrimitiveType primitiveType, GrMeshDrawOp::Target* target, - GrGeometryProcessor* geometryProcessor, const GrPipeline* pipeline, + sk_sp 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 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(); 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; } diff --git a/src/gpu/ops/GrDrawAtlasOp.cpp b/src/gpu/ops/GrDrawAtlasOp.cpp index d280ad9dff..107b0be397 100644 --- a/src/gpu/ops/GrDrawAtlasOp.cpp +++ b/src/gpu/ops/GrDrawAtlasOp.cpp @@ -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(); 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 { diff --git a/src/gpu/ops/GrDrawAtlasOp.h b/src/gpu/ops/GrDrawAtlasOp.h index 4e894ce097..d15bd3c122 100644 --- a/src/gpu/ops/GrDrawAtlasOp.h +++ b/src/gpu/ops/GrDrawAtlasOp.h @@ -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; diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h index 63986d7902..3016fd7272 100644 --- a/src/gpu/ops/GrDrawPathOp.h +++ b/src/gpu/ops/GrDrawPathOp.h @@ -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 fPath; diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp index d227920705..dd91452f5d 100644 --- a/src/gpu/ops/GrDrawVerticesOp.cpp +++ b/src/gpu/ops/GrDrawVerticesOp.cpp @@ -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 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(); 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(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; } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h index 7695dd9f87..07227e0b43 100644 --- a/src/gpu/ops/GrDrawVerticesOp.h +++ b/src/gpu/ops/GrDrawVerticesOp.h @@ -80,7 +80,7 @@ private: uint16_t* indices) const; void drawVertices(Target*, - GrGeometryProcessor*, + sk_sp, 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. diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp index 00dbef537f..4832ee721b 100644 --- a/src/gpu/ops/GrLatticeOp.cpp +++ b/src/gpu/ops/GrLatticeOp.cpp @@ -32,10 +32,10 @@ public: GrColor fColor; }; - static sk_sp Make(sk_sp proxy, + static sk_sp Make(const GrTextureProxy* proxy, sk_sp csxf, GrSamplerState::Filter filter) { - return sk_sp(new LatticeGP(std::move(proxy), std::move(csxf), filter)); + return sk_sp(new LatticeGP(proxy, std::move(csxf), filter)); } const char* name() const override { return "LatticeGP"; } @@ -92,10 +92,10 @@ public: } private: - LatticeGP(sk_sp proxy, sk_sp csxf, + LatticeGP(const GrTextureProxy* proxy, sk_sp 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 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(); 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 { diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp index 0bac5eff46..620ea47fc5 100644 --- a/src/gpu/ops/GrMeshDrawOp.cpp +++ b/src/gpu/ops/GrMeshDrawOp.cpp @@ -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(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 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(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 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 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}; diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h index e90de4706f..a6e7da5c2e 100644 --- a/src/gpu/ops/GrMeshDrawOp.h +++ b/src/gpu/ops/GrMeshDrawOp.h @@ -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 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 GrPipeline*, + const GrPipeline::FixedDynamicState*, + const GrMesh[], + int meshCount) = 0; + + /** Helper for drawing a single GrMesh. */ + void draw(sk_sp 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(std::forward(args)...); } - template - GrPipeline::FixedDynamicState* allocFixedDynamicState(Args&... args) { - return this->pipelineArena()->make( - std::forward(args)...); + GrMesh* allocMesh(GrPrimitiveType primitiveType) { + return this->pipelineArena()->make(primitiveType); + } + + GrMesh* allocMeshes(int n) { return this->pipelineArena()->makeArray(n); } + + GrPipeline::FixedDynamicState* allocFixedDynamicState(const SkIRect& rect, + int numPrimitiveProcessorTextures = 0) { + auto result = this->pipelineArena()->make(rect); + if (numPrimitiveProcessorTextures) { + result->fPrimitiveProcessorTextures = + this->allocPrimitiveProcessorTextureArray(numPrimitiveProcessorTextures); + } + return result; + } + + GrTextureProxy** allocPrimitiveProcessorTextureArray(int n) { + SkASSERT(n > 0); + return this->pipelineArena()->makeArrayDefault(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; diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp index c5542328c7..fd8a9b3c87 100644 --- a/src/gpu/ops/GrNonAAFillRectOp.cpp +++ b/src/gpu/ops/GrNonAAFillRectOp.cpp @@ -192,9 +192,9 @@ private: int rectCount = fRects.count(); sk_sp 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(); 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 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(); 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 { diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.cpp b/src/gpu/ops/GrNonAAStrokeRectOp.cpp index 21636b26dc..500b2eb2df 100644 --- a/src/gpu/ops/GrNonAAStrokeRectOp.cpp +++ b/src/gpu/ops/GrNonAAStrokeRectOp.cpp @@ -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; diff --git a/src/gpu/ops/GrOp.h b/src/gpu/ops/GrOp.h index 5c776fc05d..57e028ecd9 100644 --- a/src/gpu/ops/GrOp.h +++ b/src/gpu/ops/GrOp.h @@ -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; diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp index 54bb37c505..c0158ba0cb 100644 --- a/src/gpu/ops/GrOvalOpFactory.cpp +++ b/src/gpu/ops/GrOvalOpFactory.cpp @@ -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(); // 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(); // 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 gp(new EllipseGeometryProcessor(fStroked, localMatrix)); - QuadHelper helper; SkASSERT(sizeof(EllipseVertex) == gp->debugOnly_vertexStride()); - EllipseVertex* verts = reinterpret_cast( - helper.init(target, sizeof(EllipseVertex), fEllipses.count())); + QuadHelper helper(target, sizeof(EllipseVertex), fEllipses.count()); + EllipseVertex* verts = reinterpret_cast(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(); 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( - helper.init(target, sizeof(DIEllipseVertex), fEllipses.count())); + QuadHelper helper(target, sizeof(DIEllipseVertex), fEllipses.count()); + DIEllipseVertex* verts = reinterpret_cast(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(); 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(); // 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 indexBuffer = get_rrect_index_buffer( fStroked ? kStroke_RRectType : kFill_RRectType, target->resourceProvider()); - PatternHelper helper(GrPrimitiveType::kTriangles); - EllipseVertex* verts = reinterpret_cast( - 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(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(); 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 { diff --git a/src/gpu/ops/GrRegionOp.cpp b/src/gpu/ops/GrRegionOp.cpp index d0c24e6e73..b876295fa5 100644 --- a/src/gpu/ops/GrRegionOp.cpp +++ b/src/gpu/ops/GrRegionOp.cpp @@ -129,9 +129,9 @@ private: return; } sk_sp 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(); 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 { diff --git a/src/gpu/ops/GrSemaphoreOp.h b/src/gpu/ops/GrSemaphoreOp.h index 234c76c5d3..53c76c368b 100644 --- a/src/gpu/ops/GrSemaphoreOp.h +++ b/src/gpu/ops/GrSemaphoreOp.h @@ -34,7 +34,6 @@ protected: sk_sp fSemaphore; private: - bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; } void onPrepare(GrOpFlushState*) override {} typedef GrOp INHERITED; diff --git a/src/gpu/ops/GrShadowRRectOp.cpp b/src/gpu/ops/GrShadowRRectOp.cpp index 09a2442619..69489a2f51 100644 --- a/src/gpu/ops/GrShadowRRectOp.cpp +++ b/src/gpu/ops/GrShadowRRectOp.cpp @@ -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(); 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; diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp index 7ed74c3d7f..f1692e696a 100644 --- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp +++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp @@ -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 { diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h index 2bffa09d4c..cd72786da6 100644 --- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h +++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h @@ -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; diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp index 286fab71c7..c480bc025a 100644 --- a/src/gpu/ops/GrSmallPathRenderer.cpp +++ b/src/gpu/ops/GrSmallPathRenderer.cpp @@ -304,7 +304,7 @@ private: sk_sp fIndexBuffer; sk_sp 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(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(); 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; diff --git a/src/gpu/ops/GrStencilPathOp.h b/src/gpu/ops/GrStencilPathOp.h index 563bdc3fb4..edfcaa8943 100644 --- a/src/gpu/ops/GrStencilPathOp.h +++ b/src/gpu/ops/GrStencilPathOp.h @@ -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; diff --git a/src/gpu/ops/GrTessellatingPathRenderer.cpp b/src/gpu/ops/GrTessellatingPathRenderer.cpp index 2fea9cb053..f7228683ef 100644 --- a/src/gpu/ops/GrTessellatingPathRenderer.cpp +++ b/src/gpu/ops/GrTessellatingPathRenderer.cpp @@ -237,7 +237,7 @@ private: return path; } - void draw(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) { + void draw(Target* target, sk_sp 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(key, target->contextUniqueID())); } - void drawAA(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) { + void drawAA(Target* target, sk_sp 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 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; diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp index 72900ed0e7..2ba3639142 100644 --- a/src/gpu/ops/GrTextureOp.cpp +++ b/src/gpu/ops/GrTextureOp.cpp @@ -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 struct OptionalMultiTextureVertex; + template struct OptionalDomainVertex; template - struct OptionalMultiTextureVertex : VertexCommon { - static constexpr MultiTexture kMultiTexture = MultiTexture::kNo; - }; - template - struct OptionalMultiTextureVertex : VertexCommon { - static constexpr MultiTexture kMultiTexture = MultiTexture::kYes; - int fTextureIdx; - }; - - template struct OptionalDomainVertex; - template - struct OptionalDomainVertex : OptionalMultiTextureVertex { + struct OptionalDomainVertex : VertexCommon { static constexpr Domain kDomain = Domain::kNo; }; - template - struct OptionalDomainVertex : OptionalMultiTextureVertex { + template + struct OptionalDomainVertex : VertexCommon { static constexpr Domain kDomain = Domain::kYes; SkRect fTextureDomain; }; - template struct OptionalAAVertex; - template - struct OptionalAAVertex : OptionalDomainVertex { + template struct OptionalAAVertex; + template + struct OptionalAAVertex : OptionalDomainVertex { static constexpr GrAA kAA = GrAA::kNo; }; - template - struct OptionalAAVertex : OptionalDomainVertex { + template + struct OptionalAAVertex : OptionalDomainVertex { static constexpr GrAA kAA = GrAA::kYes; SkPoint3 fEdges[4]; }; - template - using Vertex = OptionalAAVertex; + template + using Vertex = OptionalAAVertex; - // 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 Make(sk_sp proxies[], int proxyCnt, + static sk_sp Make(GrTextureType textureType, GrPixelConfig textureConfig, + const GrSamplerState::Filter filter, sk_sp textureColorSpaceXform, sk_sp 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( - 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(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 proxies[], int proxyCnt, int samplerCnt, + TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig, + GrSamplerState::Filter filter, sk_sp textureColorSpaceXform, - sk_sp paintColorSpaceXform, - bool coverageAA, bool perspective, Domain domain, - const GrSamplerState::Filter filters[], const GrShaderCaps& caps) + sk_sp 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 fTextureColorSpaceXform; sk_sp fPaintColorSpaceXform; - TextureSampler fSamplers[1]; + TextureSampler fSampler; typedef GrGeometryProcessor INHERITED; }; @@ -527,20 +435,6 @@ private: } }; -template struct TexIdAssigner; - -template struct TexIdAssigner { - static void Assign(V* vertices, int textureIdx) { - for (int i = 0; i < 4; ++i) { - vertices[i].fTextureIdx = textureIdx; - } - } -}; - -template struct TexIdAssigner { - static void Assign(V* vertices, int textureIdx) {} -}; - template struct DomainAssigner; template struct DomainAssigner { @@ -585,7 +479,7 @@ template struct DomainAssigner { template 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::Assign(vertices, textureIdx); DomainAssigner::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(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(this->filters()[i])); - } + str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(), + static_cast(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(SkTMax(rect.width(), 1.f) * SkTMax(rect.height(), 1.f)); - } - - static constexpr int kMaxTextures = TextureGeometryProcessor::kMaxTextures; - TextureOp(sk_sp 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(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(draw.domain()); - fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds); } - template - void tess(void* v, const float iw[], const float ih[], const GrGeometryProcessor* gp) { - using Vertex = TextureGeometryProcessor::Vertex; + template + void tess(void* v, const GrGeometryProcessor* gp) { + using Vertex = TextureGeometryProcessor::Vertex; SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex)); auto vertices = static_cast(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(draw.quad(), draw.srcRect(), draw.color(), origin, - filters[textureIdx], vertices, iw[textureIdx], ih[textureIdx], - textureIdx, draw.domain()); + tessellate_quad(draw.quad(), draw.srcRect(), draw.color(), origin, fFilter, + vertices, iw, ih, draw.domain()); vertices += 4; } } void onPrepareDraws(Target* target) override { - sk_sp 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 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); -#define TESS_FN_AND_VERTEX_SIZE(Point, MT, Domain, AA) \ - { \ - &TextureOp::tess, \ - sizeof(TextureGeometryProcessor::Vertex) \ + using TessFn = decltype(&TextureOp::tess); +#define TESS_FN_AND_VERTEX_SIZE(Point, Domain, AA) \ + { \ + &TextureOp::tess, \ + sizeof(TextureGeometryProcessor::Vertex) \ } 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 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(); - 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(mem); - auto filters = reinterpret_cast(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(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(fAAType); } - GrTextureProxy* const* proxies() const { return fProxyCnt > 1 ? fProxyArray : &fProxy0; } - - const GrSamplerState::Filter* filters() const { - if (fProxyCnt > 1) { - return reinterpret_cast(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 fTextureColorSpaceXform; sk_sp 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 { diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp index 013c1d7815..3cbc6adf51 100644 --- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp +++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp @@ -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()) { diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp index 04a85a42e0..011db9df9a 100644 --- a/src/gpu/vk/GrVkPipelineState.cpp +++ b/src/gpu/vk/GrVkPipelineState.cpp @@ -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(sampler.peekTexture())}; + auto texture = static_cast(primProcTextures[i]->peekTexture()); + samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture}; } GrFragmentProcessor::Iter iter(pipeline); diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h index 1df4bb5348..d61359c08b 100644 --- a/src/gpu/vk/GrVkPipelineState.h +++ b/src/gpu/vk/GrVkPipelineState.h @@ -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); diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp index 3417a7eb37..1cb2b7c165 100644 --- a/tests/GrMeshTest.cpp +++ b/tests/GrMeshTest.cpp @@ -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); diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp index 8752e61e7f..622790beca 100644 --- a/tests/GrPipelineDynamicStateTest.cpp +++ b/tests/GrPipelineDynamicStateTest.cpp @@ -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; diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp index 99f9d2a8e3..1b65585c7a 100644 --- a/tests/LazyProxyTest.cpp +++ b/tests/LazyProxyTest.cpp @@ -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 {} diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp index efbc43a6ef..f992e5317d 100644 --- a/tests/OnFlushCallbackTest.cpp +++ b/tests/OnFlushCallbackTest.cpp @@ -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; diff --git a/tests/PrimitiveProcessorTest.cpp b/tests/PrimitiveProcessorTest.cpp index 661c1ce7f1..5f9fbe5223 100644 --- a/tests/PrimitiveProcessorTest.cpp +++ b/tests/PrimitiveProcessorTest.cpp @@ -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 gp(new GP(fNumAttribs)); - QuadHelper helper; size_t vertexStride = fNumAttribs * GrVertexAttribTypeSize(kFloat2_GrVertexAttribType); SkASSERT(vertexStride == gp->debugOnly_vertexStride()); - SkPoint* vertices = reinterpret_cast(helper.init(target, vertexStride, 1)); + QuadHelper helper(target, vertexStride, 1); + SkPoint* vertices = reinterpret_cast(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; diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp index 9b7e93bc56..0a7ad7566e 100644 --- a/tests/ProcessorTest.cpp +++ b/tests/ProcessorTest.cpp @@ -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;