GrDrawVerticesOp.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/core/SkRectPriv.h"
  8. #include "src/gpu/GrCaps.h"
  9. #include "src/gpu/GrDefaultGeoProcFactory.h"
  10. #include "src/gpu/GrOpFlushState.h"
  11. #include "src/gpu/SkGr.h"
  12. #include "src/gpu/ops/GrDrawVerticesOp.h"
  13. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  14. namespace {
  15. class DrawVerticesOp final : public GrMeshDrawOp {
  16. private:
  17. using Helper = GrSimpleMeshDrawOpHelper;
  18. public:
  19. DEFINE_OP_CLASS_ID
  20. DrawVerticesOp(const Helper::MakeArgs&, const SkPMColor4f&, sk_sp<SkVertices>,
  21. const SkVertices::Bone bones[], int boneCount, GrPrimitiveType, GrAAType,
  22. sk_sp<GrColorSpaceXform>, const SkMatrix& viewMatrix);
  23. const char* name() const override { return "DrawVerticesOp"; }
  24. void visitProxies(const VisitProxyFunc& func) const override {
  25. fHelper.visitProxies(func);
  26. }
  27. #ifdef SK_DEBUG
  28. SkString dumpInfo() const override;
  29. #endif
  30. FixedFunctionFlags fixedFunctionFlags() const override;
  31. GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
  32. bool hasMixedSampledCoverage, GrClampType) override;
  33. private:
  34. enum class ColorArrayType {
  35. kPremulGrColor,
  36. kSkColor,
  37. };
  38. void onPrepareDraws(Target*) override;
  39. void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
  40. void drawVolatile(Target*);
  41. void drawNonVolatile(Target*);
  42. void fillBuffers(bool hasColorAttribute,
  43. bool hasLocalCoordsAttribute,
  44. size_t vertexStride,
  45. void* verts,
  46. uint16_t* indices) const;
  47. void drawVertices(Target*,
  48. sk_sp<const GrGeometryProcessor>,
  49. sk_sp<const GrBuffer> vertexBuffer,
  50. int firstVertex,
  51. sk_sp<const GrBuffer> indexBuffer,
  52. int firstIndex);
  53. sk_sp<GrGeometryProcessor> makeGP(const GrShaderCaps* shaderCaps,
  54. bool* hasColorAttribute,
  55. bool* hasLocalCoordAttribute) const;
  56. GrPrimitiveType primitiveType() const { return fPrimitiveType; }
  57. bool combinablePrimitive() const {
  58. return GrPrimitiveType::kTriangles == fPrimitiveType ||
  59. GrPrimitiveType::kLines == fPrimitiveType ||
  60. GrPrimitiveType::kPoints == fPrimitiveType;
  61. }
  62. CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
  63. struct Mesh {
  64. SkPMColor4f fColor; // Used if this->hasPerVertexColors() is false.
  65. sk_sp<SkVertices> fVertices;
  66. SkMatrix fViewMatrix;
  67. bool fIgnoreTexCoords;
  68. bool fIgnoreColors;
  69. bool hasExplicitLocalCoords() const {
  70. return fVertices->hasTexCoords() && !fIgnoreTexCoords;
  71. }
  72. bool hasPerVertexColors() const {
  73. return fVertices->hasColors() && !fIgnoreColors;
  74. }
  75. };
  76. bool isIndexed() const {
  77. // Consistency enforced in onCombineIfPossible.
  78. return fMeshes[0].fVertices->hasIndices();
  79. }
  80. bool requiresPerVertexColors() const {
  81. return SkToBool(kRequiresPerVertexColors_Flag & fFlags);
  82. }
  83. bool anyMeshHasExplicitLocalCoords() const {
  84. return SkToBool(kAnyMeshHasExplicitLocalCoords_Flag & fFlags);
  85. }
  86. bool hasMultipleViewMatrices() const {
  87. return SkToBool(kHasMultipleViewMatrices_Flag & fFlags);
  88. }
  89. enum Flags {
  90. kRequiresPerVertexColors_Flag = 0x1,
  91. kAnyMeshHasExplicitLocalCoords_Flag = 0x2,
  92. kHasMultipleViewMatrices_Flag = 0x4,
  93. };
  94. Helper fHelper;
  95. SkSTArray<1, Mesh, true> fMeshes;
  96. // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore
  97. // the SkVertices mode (though fPrimitiveType may have been inferred from it).
  98. GrPrimitiveType fPrimitiveType;
  99. uint32_t fFlags;
  100. int fVertexCount;
  101. int fIndexCount;
  102. ColorArrayType fColorArrayType;
  103. sk_sp<GrColorSpaceXform> fColorSpaceXform;
  104. typedef GrMeshDrawOp INHERITED;
  105. };
  106. DrawVerticesOp::DrawVerticesOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
  107. sk_sp<SkVertices> vertices, const SkVertices::Bone bones[],
  108. int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
  109. sk_sp<GrColorSpaceXform> colorSpaceXform,
  110. const SkMatrix& viewMatrix)
  111. : INHERITED(ClassID())
  112. , fHelper(helperArgs, aaType)
  113. , fPrimitiveType(primitiveType)
  114. , fColorSpaceXform(std::move(colorSpaceXform)) {
  115. SkASSERT(vertices);
  116. fVertexCount = vertices->vertexCount();
  117. fIndexCount = vertices->indexCount();
  118. fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor
  119. : ColorArrayType::kPremulGrColor;
  120. Mesh& mesh = fMeshes.push_back();
  121. mesh.fColor = color;
  122. mesh.fViewMatrix = viewMatrix;
  123. mesh.fVertices = std::move(vertices);
  124. mesh.fIgnoreTexCoords = false;
  125. mesh.fIgnoreColors = false;
  126. if (mesh.fVertices->hasBones() && bones) {
  127. // Perform the transformations on the CPU instead of the GPU.
  128. mesh.fVertices = mesh.fVertices->applyBones(bones, boneCount);
  129. } else {
  130. SkASSERT(!bones || boneCount == 1);
  131. }
  132. fFlags = 0;
  133. if (mesh.hasPerVertexColors()) {
  134. fFlags |= kRequiresPerVertexColors_Flag;
  135. }
  136. if (mesh.hasExplicitLocalCoords()) {
  137. fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
  138. }
  139. // Special case for meshes with a world transform but no bone weights.
  140. // These will be considered normal vertices draws without bones.
  141. if (!mesh.fVertices->hasBones() && boneCount == 1) {
  142. SkMatrix worldTransform;
  143. worldTransform.setAffine(bones[0].values);
  144. mesh.fViewMatrix.preConcat(worldTransform);
  145. }
  146. IsZeroArea zeroArea;
  147. if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
  148. zeroArea = IsZeroArea::kYes;
  149. } else {
  150. zeroArea = IsZeroArea::kNo;
  151. }
  152. this->setTransformedBounds(mesh.fVertices->bounds(),
  153. mesh.fViewMatrix,
  154. HasAABloat::kNo,
  155. zeroArea);
  156. }
  157. #ifdef SK_DEBUG
  158. SkString DrawVerticesOp::dumpInfo() const {
  159. SkString string;
  160. string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
  161. fMeshes.count(), fVertexCount, fIndexCount);
  162. string += fHelper.dumpInfo();
  163. string += INHERITED::dumpInfo();
  164. return string;
  165. }
  166. #endif
  167. GrDrawOp::FixedFunctionFlags DrawVerticesOp::fixedFunctionFlags() const {
  168. return fHelper.fixedFunctionFlags();
  169. }
  170. GrProcessorSet::Analysis DrawVerticesOp::finalize(
  171. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  172. GrClampType clampType) {
  173. GrProcessorAnalysisColor gpColor;
  174. if (this->requiresPerVertexColors()) {
  175. gpColor.setToUnknown();
  176. } else {
  177. gpColor.setToConstant(fMeshes.front().fColor);
  178. }
  179. auto result = fHelper.finalizeProcessors(caps, clip, hasMixedSampledCoverage, clampType,
  180. GrProcessorAnalysisCoverage::kNone, &gpColor);
  181. if (gpColor.isConstant(&fMeshes.front().fColor)) {
  182. fMeshes.front().fIgnoreColors = true;
  183. fFlags &= ~kRequiresPerVertexColors_Flag;
  184. fColorArrayType = ColorArrayType::kPremulGrColor;
  185. }
  186. if (!fHelper.usesLocalCoords()) {
  187. fMeshes[0].fIgnoreTexCoords = true;
  188. fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag;
  189. }
  190. return result;
  191. }
  192. sk_sp<GrGeometryProcessor> DrawVerticesOp::makeGP(const GrShaderCaps* shaderCaps,
  193. bool* hasColorAttribute,
  194. bool* hasLocalCoordAttribute) const {
  195. using namespace GrDefaultGeoProcFactory;
  196. LocalCoords::Type localCoordsType;
  197. if (fHelper.usesLocalCoords()) {
  198. // If we have multiple view matrices we will transform the positions into device space. We
  199. // must then also provide untransformed positions as local coords.
  200. if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
  201. *hasLocalCoordAttribute = true;
  202. localCoordsType = LocalCoords::kHasExplicit_Type;
  203. } else {
  204. *hasLocalCoordAttribute = false;
  205. localCoordsType = LocalCoords::kUsePosition_Type;
  206. }
  207. } else {
  208. localCoordsType = LocalCoords::kUnused_Type;
  209. *hasLocalCoordAttribute = false;
  210. }
  211. Color color(fMeshes[0].fColor);
  212. if (this->requiresPerVertexColors()) {
  213. if (fColorArrayType == ColorArrayType::kPremulGrColor) {
  214. color.fType = Color::kPremulGrColorAttribute_Type;
  215. } else {
  216. color.fType = Color::kUnpremulSkColorAttribute_Type;
  217. color.fColorSpaceXform = fColorSpaceXform;
  218. }
  219. *hasColorAttribute = true;
  220. } else {
  221. *hasColorAttribute = false;
  222. }
  223. const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
  224. return GrDefaultGeoProcFactory::Make(shaderCaps,
  225. color,
  226. Coverage::kSolid_Type,
  227. localCoordsType,
  228. vm);
  229. }
  230. void DrawVerticesOp::onPrepareDraws(Target* target) {
  231. bool hasMapBufferSupport = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
  232. if (fMeshes[0].fVertices->isVolatile() || !hasMapBufferSupport) {
  233. this->drawVolatile(target);
  234. } else {
  235. this->drawNonVolatile(target);
  236. }
  237. }
  238. void DrawVerticesOp::drawVolatile(Target* target) {
  239. bool hasColorAttribute;
  240. bool hasLocalCoordsAttribute;
  241. sk_sp<GrGeometryProcessor> gp = this->makeGP(target->caps().shaderCaps(),
  242. &hasColorAttribute,
  243. &hasLocalCoordsAttribute);
  244. // Allocate buffers.
  245. size_t vertexStride = gp->vertexStride();
  246. sk_sp<const GrBuffer> vertexBuffer;
  247. int firstVertex = 0;
  248. void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
  249. if (!verts) {
  250. SkDebugf("Could not allocate vertices\n");
  251. return;
  252. }
  253. sk_sp<const GrBuffer> indexBuffer;
  254. int firstIndex = 0;
  255. uint16_t* indices = nullptr;
  256. if (this->isIndexed()) {
  257. indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
  258. if (!indices) {
  259. SkDebugf("Could not allocate indices\n");
  260. return;
  261. }
  262. }
  263. // Fill the buffers.
  264. this->fillBuffers(hasColorAttribute,
  265. hasLocalCoordsAttribute,
  266. vertexStride,
  267. verts,
  268. indices);
  269. // Draw the vertices.
  270. this->drawVertices(target, std::move(gp), std::move(vertexBuffer), firstVertex, indexBuffer,
  271. firstIndex);
  272. }
  273. void DrawVerticesOp::drawNonVolatile(Target* target) {
  274. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  275. bool hasColorAttribute;
  276. bool hasLocalCoordsAttribute;
  277. sk_sp<GrGeometryProcessor> gp = this->makeGP(target->caps().shaderCaps(),
  278. &hasColorAttribute,
  279. &hasLocalCoordsAttribute);
  280. SkASSERT(fMeshes.count() == 1); // Non-volatile meshes should never combine.
  281. // Get the resource provider.
  282. GrResourceProvider* rp = target->resourceProvider();
  283. // Generate keys for the buffers.
  284. GrUniqueKey vertexKey, indexKey;
  285. GrUniqueKey::Builder vertexKeyBuilder(&vertexKey, kDomain, 2);
  286. GrUniqueKey::Builder indexKeyBuilder(&indexKey, kDomain, 2);
  287. vertexKeyBuilder[0] = indexKeyBuilder[0] = fMeshes[0].fVertices->uniqueID();
  288. vertexKeyBuilder[1] = 0;
  289. indexKeyBuilder[1] = 1;
  290. vertexKeyBuilder.finish();
  291. indexKeyBuilder.finish();
  292. // Try to grab data from the cache.
  293. sk_sp<GrGpuBuffer> vertexBuffer = rp->findByUniqueKey<GrGpuBuffer>(vertexKey);
  294. sk_sp<GrGpuBuffer> indexBuffer =
  295. this->isIndexed() ? rp->findByUniqueKey<GrGpuBuffer>(indexKey) : nullptr;
  296. // Draw using the cached buffers if possible.
  297. if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
  298. this->drawVertices(target, std::move(gp), std::move(vertexBuffer), 0,
  299. std::move(indexBuffer), 0);
  300. return;
  301. }
  302. // Allocate vertex buffer.
  303. size_t vertexStride = gp->vertexStride();
  304. vertexBuffer = rp->createBuffer(
  305. fVertexCount * vertexStride, GrGpuBufferType::kVertex, kStatic_GrAccessPattern);
  306. void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
  307. if (!verts) {
  308. SkDebugf("Could not allocate vertices\n");
  309. return;
  310. }
  311. // Allocate index buffer.
  312. uint16_t* indices = nullptr;
  313. if (this->isIndexed()) {
  314. indexBuffer = rp->createBuffer(
  315. fIndexCount * sizeof(uint16_t), GrGpuBufferType::kIndex, kStatic_GrAccessPattern);
  316. indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr;
  317. if (!indices) {
  318. SkDebugf("Could not allocate indices\n");
  319. return;
  320. }
  321. }
  322. // Fill the buffers.
  323. this->fillBuffers(hasColorAttribute,
  324. hasLocalCoordsAttribute,
  325. vertexStride,
  326. verts,
  327. indices);
  328. // Unmap the buffers.
  329. vertexBuffer->unmap();
  330. if (indexBuffer) {
  331. indexBuffer->unmap();
  332. }
  333. // Cache the buffers.
  334. rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get());
  335. rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
  336. // Draw the vertices.
  337. this->drawVertices(target, std::move(gp), std::move(vertexBuffer), 0, std::move(indexBuffer),
  338. 0);
  339. }
  340. void DrawVerticesOp::fillBuffers(bool hasColorAttribute,
  341. bool hasLocalCoordsAttribute,
  342. size_t vertexStride,
  343. void* verts,
  344. uint16_t* indices) const {
  345. int instanceCount = fMeshes.count();
  346. // Copy data into the buffers.
  347. int vertexOffset = 0;
  348. // We have a fast case below for uploading the vertex data when the matrix is translate
  349. // only and there are colors but not local coords.
  350. bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute;
  351. for (int i = 0; i < instanceCount; i++) {
  352. // Get each mesh.
  353. const Mesh& mesh = fMeshes[i];
  354. // Copy data into the index buffer.
  355. if (indices) {
  356. int indexCount = mesh.fVertices->indexCount();
  357. for (int j = 0; j < indexCount; ++j) {
  358. *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
  359. }
  360. }
  361. // Copy data into the vertex buffer.
  362. int vertexCount = mesh.fVertices->vertexCount();
  363. const SkPoint* positions = mesh.fVertices->positions();
  364. const SkColor* colors = mesh.fVertices->colors();
  365. const SkPoint* localCoords = mesh.fVertices->texCoords();
  366. bool fastMesh = (!this->hasMultipleViewMatrices() ||
  367. mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
  368. mesh.hasPerVertexColors();
  369. if (fastAttrs && fastMesh) {
  370. // Fast case.
  371. struct V {
  372. SkPoint fPos;
  373. uint32_t fColor;
  374. };
  375. SkASSERT(sizeof(V) == vertexStride);
  376. V* v = (V*)verts;
  377. Sk2f t(0, 0);
  378. if (this->hasMultipleViewMatrices()) {
  379. t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
  380. }
  381. for (int j = 0; j < vertexCount; ++j) {
  382. Sk2f p = Sk2f::Load(positions++) + t;
  383. p.store(&v[j].fPos);
  384. v[j].fColor = colors[j];
  385. }
  386. verts = v + vertexCount;
  387. } else {
  388. // Normal case.
  389. static constexpr size_t kColorOffset = sizeof(SkPoint);
  390. size_t offset = kColorOffset;
  391. if (hasColorAttribute) {
  392. offset += sizeof(uint32_t);
  393. }
  394. size_t localCoordOffset = offset;
  395. if (hasLocalCoordsAttribute) {
  396. offset += sizeof(SkPoint);
  397. }
  398. // TODO4F: Preserve float colors
  399. GrColor color = mesh.fColor.toBytes_RGBA();
  400. for (int j = 0; j < vertexCount; ++j) {
  401. if (this->hasMultipleViewMatrices()) {
  402. mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
  403. } else {
  404. *((SkPoint*)verts) = positions[j];
  405. }
  406. if (hasColorAttribute) {
  407. if (mesh.hasPerVertexColors()) {
  408. *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
  409. } else {
  410. *(uint32_t*)((intptr_t)verts + kColorOffset) = color;
  411. }
  412. }
  413. if (hasLocalCoordsAttribute) {
  414. if (mesh.hasExplicitLocalCoords()) {
  415. *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
  416. } else {
  417. *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
  418. }
  419. }
  420. verts = (void*)((intptr_t)verts + vertexStride);
  421. }
  422. }
  423. vertexOffset += vertexCount;
  424. }
  425. }
  426. void DrawVerticesOp::drawVertices(Target* target,
  427. sk_sp<const GrGeometryProcessor> gp,
  428. sk_sp<const GrBuffer> vertexBuffer,
  429. int firstVertex,
  430. sk_sp<const GrBuffer> indexBuffer,
  431. int firstIndex) {
  432. GrMesh* mesh = target->allocMesh(this->primitiveType());
  433. if (this->isIndexed()) {
  434. mesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
  435. GrPrimitiveRestart::kNo);
  436. } else {
  437. mesh->setNonIndexedNonInstanced(fVertexCount);
  438. }
  439. mesh->setVertexData(std::move(vertexBuffer), firstVertex);
  440. target->recordDraw(std::move(gp), mesh);
  441. }
  442. void DrawVerticesOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
  443. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  444. }
  445. GrOp::CombineResult DrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
  446. DrawVerticesOp* that = t->cast<DrawVerticesOp>();
  447. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
  448. return CombineResult::kCannotCombine;
  449. }
  450. // Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
  451. // then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
  452. // that was saved in its vertex buffer, which is not necessarily there anymore.
  453. if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
  454. return CombineResult::kCannotCombine;
  455. }
  456. if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
  457. return CombineResult::kCannotCombine;
  458. }
  459. if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
  460. return CombineResult::kCannotCombine;
  461. }
  462. if (fColorArrayType != that->fColorArrayType) {
  463. return CombineResult::kCannotCombine;
  464. }
  465. if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
  466. return CombineResult::kCannotCombine;
  467. }
  468. // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
  469. // gamut is determined by the render target context. A mis-match should be impossible.
  470. SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
  471. // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
  472. // with multiple view matrices.
  473. fFlags |= that->fFlags;
  474. if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
  475. fFlags |= kRequiresPerVertexColors_Flag;
  476. }
  477. // Check whether we are about to acquire a mesh with a different view matrix.
  478. if (!this->hasMultipleViewMatrices() &&
  479. !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
  480. fFlags |= kHasMultipleViewMatrices_Flag;
  481. }
  482. fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
  483. fVertexCount += that->fVertexCount;
  484. fIndexCount += that->fIndexCount;
  485. return CombineResult::kMerged;
  486. }
  487. } // anonymous namespace
  488. std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrRecordingContext* context,
  489. GrPaint&& paint,
  490. sk_sp<SkVertices> vertices,
  491. const SkVertices::Bone bones[],
  492. int boneCount,
  493. const SkMatrix& viewMatrix,
  494. GrAAType aaType,
  495. sk_sp<GrColorSpaceXform> colorSpaceXform,
  496. GrPrimitiveType* overridePrimType) {
  497. SkASSERT(vertices);
  498. GrPrimitiveType primType = overridePrimType ? *overridePrimType
  499. : SkVertexModeToGrPrimitiveType(vertices->mode());
  500. return GrSimpleMeshDrawOpHelper::FactoryHelper<DrawVerticesOp>(context, std::move(paint),
  501. std::move(vertices),
  502. bones, boneCount,
  503. primType, aaType,
  504. std::move(colorSpaceXform),
  505. viewMatrix);
  506. }
  507. ///////////////////////////////////////////////////////////////////////////////////////////////////
  508. #if GR_TEST_UTILS
  509. #include "src/gpu/GrDrawOpTest.h"
  510. static uint32_t seed_vertices(GrPrimitiveType type) {
  511. switch (type) {
  512. case GrPrimitiveType::kTriangles:
  513. case GrPrimitiveType::kTriangleStrip:
  514. return 3;
  515. case GrPrimitiveType::kPoints:
  516. return 1;
  517. case GrPrimitiveType::kLines:
  518. case GrPrimitiveType::kLineStrip:
  519. return 2;
  520. case GrPrimitiveType::kLinesAdjacency:
  521. return 4;
  522. }
  523. SK_ABORT("Incomplete switch\n");
  524. return 0;
  525. }
  526. static uint32_t primitive_vertices(GrPrimitiveType type) {
  527. switch (type) {
  528. case GrPrimitiveType::kTriangles:
  529. return 3;
  530. case GrPrimitiveType::kLines:
  531. return 2;
  532. case GrPrimitiveType::kTriangleStrip:
  533. case GrPrimitiveType::kPoints:
  534. case GrPrimitiveType::kLineStrip:
  535. return 1;
  536. case GrPrimitiveType::kLinesAdjacency:
  537. return 4;
  538. }
  539. SK_ABORT("Incomplete switch\n");
  540. return 0;
  541. }
  542. static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
  543. SkPoint p;
  544. p.fX = random->nextRangeScalar(min, max);
  545. p.fY = random->nextRangeScalar(min, max);
  546. return p;
  547. }
  548. static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
  549. SkRandom* random, SkTArray<SkPoint>* positions,
  550. SkTArray<SkPoint>* texCoords, bool hasTexCoords,
  551. SkTArray<uint32_t>* colors, bool hasColors,
  552. SkTArray<uint16_t>* indices, bool hasIndices) {
  553. for (uint32_t v = 0; v < count; v++) {
  554. positions->push_back(random_point(random, min, max));
  555. if (hasTexCoords) {
  556. texCoords->push_back(random_point(random, min, max));
  557. }
  558. if (hasColors) {
  559. colors->push_back(GrRandomColor(random));
  560. }
  561. if (hasIndices) {
  562. SkASSERT(maxVertex <= UINT16_MAX);
  563. indices->push_back(random->nextULessThan((uint16_t)maxVertex));
  564. }
  565. }
  566. }
  567. GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp) {
  568. GrPrimitiveType type;
  569. do {
  570. type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
  571. } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
  572. !context->priv().caps()->shaderCaps()->geometryShaderSupport());
  573. uint32_t primitiveCount = random->nextRangeU(1, 100);
  574. // TODO make 'sensible' indexbuffers
  575. SkTArray<SkPoint> positions;
  576. SkTArray<SkPoint> texCoords;
  577. SkTArray<uint32_t> colors;
  578. SkTArray<uint16_t> indices;
  579. bool hasTexCoords = random->nextBool();
  580. bool hasIndices = random->nextBool();
  581. bool hasColors = random->nextBool();
  582. uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
  583. static const SkScalar kMinVertExtent = -100.f;
  584. static const SkScalar kMaxVertExtent = 100.f;
  585. randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
  586. &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
  587. hasIndices);
  588. for (uint32_t i = 1; i < primitiveCount; i++) {
  589. randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
  590. random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
  591. hasIndices);
  592. }
  593. SkMatrix viewMatrix = GrTest::TestMatrix(random);
  594. sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
  595. static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
  596. sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
  597. texCoords.begin(), colors.begin(),
  598. hasIndices ? indices.count() : 0,
  599. indices.begin());
  600. GrAAType aaType = GrAAType::kNone;
  601. if (numSamples > 1 && random->nextBool()) {
  602. aaType = GrAAType::kMSAA;
  603. }
  604. return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0,
  605. viewMatrix, aaType, std::move(colorSpaceXform), &type);
  606. }
  607. #endif