1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 9cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 10cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 14cb93a386Sopenharmony_ci#include "src/gpu/ops/GrOp.h" 15cb93a386Sopenharmony_ci#include "src/gpu/ops/OpsTask.h" 16cb93a386Sopenharmony_ci#include "tests/Test.h" 17cb93a386Sopenharmony_ci#include <iterator> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci// We create Ops that write a value into a range of a buffer. We create ranges from 20cb93a386Sopenharmony_ci// kNumOpPositions starting positions x kRanges canonical ranges. We repeat each range kNumRepeats 21cb93a386Sopenharmony_ci// times (with a different value written by each of the repeats). 22cb93a386Sopenharmony_cinamespace { 23cb93a386Sopenharmony_cistruct Range { 24cb93a386Sopenharmony_ci unsigned fOffset; 25cb93a386Sopenharmony_ci unsigned fLength; 26cb93a386Sopenharmony_ci}; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cistatic constexpr int kNumOpPositions = 4; 29cb93a386Sopenharmony_cistatic constexpr Range kRanges[] = {{0, 4,}, {1, 2}}; 30cb93a386Sopenharmony_cistatic constexpr int kNumRanges = (int)SK_ARRAY_COUNT(kRanges); 31cb93a386Sopenharmony_cistatic constexpr int kNumRepeats = 2; 32cb93a386Sopenharmony_cistatic constexpr int kNumOps = kNumRepeats * kNumOpPositions * kNumRanges; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cistatic constexpr uint64_t fact(int n) { 35cb93a386Sopenharmony_ci assert(n > 0); 36cb93a386Sopenharmony_ci return n > 1 ? n * fact(n - 1) : 1; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci// How wide should our result buffer be to hold values written by the ranges of the ops. 40cb93a386Sopenharmony_cistatic constexpr unsigned result_width() { 41cb93a386Sopenharmony_ci unsigned maxLength = 0; 42cb93a386Sopenharmony_ci for (size_t i = 0; i < kNumRanges; ++i) { 43cb93a386Sopenharmony_ci maxLength = maxLength > kRanges[i].fLength ? maxLength : kRanges[i].fLength; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci return kNumOpPositions + maxLength - 1; 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci// Number of possible allowable binary chainings among the kNumOps ops. 49cb93a386Sopenharmony_cistatic constexpr int kNumCombinableValues = fact(kNumOps) / fact(kNumOps - 2); 50cb93a386Sopenharmony_ciusing Combinable = std::array<GrOp::CombineResult, kNumCombinableValues>; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci/** 53cb93a386Sopenharmony_ci * The index in Combinable for the result for combining op 'b' into op 'a', i.e. the result of 54cb93a386Sopenharmony_ci * op[a]->combineIfPossible(op[b]). 55cb93a386Sopenharmony_ci */ 56cb93a386Sopenharmony_ciint64_t combinable_index(int a, int b) { 57cb93a386Sopenharmony_ci SkASSERT(b != a); 58cb93a386Sopenharmony_ci // Each index gets kNumOps - 1 contiguous bools 59cb93a386Sopenharmony_ci int64_t aOffset = a * (kNumOps - 1); 60cb93a386Sopenharmony_ci // Within a's range we have one value each other op, but not one for a itself. 61cb93a386Sopenharmony_ci int64_t bIdxInA = b < a ? b : b - 1; 62cb93a386Sopenharmony_ci return aOffset + bIdxInA; 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci/** 66cb93a386Sopenharmony_ci * Creates a legal set of combinability results for the ops. The likelihood that any two ops 67cb93a386Sopenharmony_ci * in a group can merge is randomly chosen. 68cb93a386Sopenharmony_ci */ 69cb93a386Sopenharmony_cistatic void init_combinable(int numGroups, Combinable* combinable, SkRandom* random) { 70cb93a386Sopenharmony_ci SkScalar mergeProbability = random->nextUScalar1(); 71cb93a386Sopenharmony_ci std::fill_n(combinable->begin(), kNumCombinableValues, GrOp::CombineResult::kCannotCombine); 72cb93a386Sopenharmony_ci SkTDArray<int> groups[kNumOps]; 73cb93a386Sopenharmony_ci for (int i = 0; i < kNumOps; ++i) { 74cb93a386Sopenharmony_ci auto& group = groups[random->nextULessThan(numGroups)]; 75cb93a386Sopenharmony_ci for (int g = 0; g < group.count(); ++g) { 76cb93a386Sopenharmony_ci int j = group[g]; 77cb93a386Sopenharmony_ci if (random->nextUScalar1() < mergeProbability) { 78cb93a386Sopenharmony_ci (*combinable)[combinable_index(i, j)] = GrOp::CombineResult::kMerged; 79cb93a386Sopenharmony_ci } else { 80cb93a386Sopenharmony_ci (*combinable)[combinable_index(i, j)] = GrOp::CombineResult::kMayChain; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci if (random->nextUScalar1() < mergeProbability) { 83cb93a386Sopenharmony_ci (*combinable)[combinable_index(j, i)] = GrOp::CombineResult::kMerged; 84cb93a386Sopenharmony_ci } else { 85cb93a386Sopenharmony_ci (*combinable)[combinable_index(j, i)] = GrOp::CombineResult::kMayChain; 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci group.push_back(i); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci} 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci/** 93cb93a386Sopenharmony_ci * A simple test op. It has an integer position, p. When it executes it writes p into an array 94cb93a386Sopenharmony_ci * of ints at index p and p+1. It takes a bitfield that indicates allowed pair-wise chainings. 95cb93a386Sopenharmony_ci */ 96cb93a386Sopenharmony_ciclass TestOp : public GrOp { 97cb93a386Sopenharmony_cipublic: 98cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, int value, const Range& range, 101cb93a386Sopenharmony_ci int result[], const Combinable* combinable) { 102cb93a386Sopenharmony_ci return GrOp::Make<TestOp>(context, value, range, result, combinable); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci const char* name() const override { return "TestOp"; } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci void writeResult(int result[]) const { 108cb93a386Sopenharmony_ci for (const auto& op : ChainRange<TestOp>(this)) { 109cb93a386Sopenharmony_ci for (const auto& vr : op.fValueRanges) { 110cb93a386Sopenharmony_ci for (unsigned i = 0; i < vr.fRange.fLength; ++i) { 111cb93a386Sopenharmony_ci result[vr.fRange.fOffset + i] = vr.fValue; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ciprivate: 118cb93a386Sopenharmony_ci friend class ::GrOp; // for ctor 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci TestOp(int value, const Range& range, int result[], const Combinable* combinable) 121cb93a386Sopenharmony_ci : INHERITED(ClassID()), fResult(result), fCombinable(combinable) { 122cb93a386Sopenharmony_ci fValueRanges.push_back({value, range}); 123cb93a386Sopenharmony_ci this->setBounds(SkRect::MakeXYWH(range.fOffset, 0, range.fOffset + range.fLength, 1), 124cb93a386Sopenharmony_ci HasAABloat::kNo, IsHairline::kNo); 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci void onPrePrepare(GrRecordingContext*, 128cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 129cb93a386Sopenharmony_ci GrAppliedClip*, 130cb93a386Sopenharmony_ci const GrDstProxyView&, 131cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 132cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override {} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci void onPrepare(GrOpFlushState*) override {} 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci void onExecute(GrOpFlushState*, const SkRect& chainBounds) override { 137cb93a386Sopenharmony_ci for (auto& op : ChainRange<TestOp>(this)) { 138cb93a386Sopenharmony_ci op.writeResult(fResult); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc* arenas, const GrCaps&) override { 143cb93a386Sopenharmony_ci // This op doesn't use the arenas, but make sure the OpsTask is sending it 144cb93a386Sopenharmony_ci SkASSERT(arenas); 145cb93a386Sopenharmony_ci (void) arenas; 146cb93a386Sopenharmony_ci auto that = t->cast<TestOp>(); 147cb93a386Sopenharmony_ci int v0 = fValueRanges[0].fValue; 148cb93a386Sopenharmony_ci int v1 = that->fValueRanges[0].fValue; 149cb93a386Sopenharmony_ci auto result = (*fCombinable)[combinable_index(v0, v1)]; 150cb93a386Sopenharmony_ci if (result == GrOp::CombineResult::kMerged) { 151cb93a386Sopenharmony_ci std::move(that->fValueRanges.begin(), that->fValueRanges.end(), 152cb93a386Sopenharmony_ci std::back_inserter(fValueRanges)); 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci return result; 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci struct ValueRange { 158cb93a386Sopenharmony_ci int fValue; 159cb93a386Sopenharmony_ci Range fRange; 160cb93a386Sopenharmony_ci }; 161cb93a386Sopenharmony_ci std::vector<ValueRange> fValueRanges; 162cb93a386Sopenharmony_ci int* fResult; 163cb93a386Sopenharmony_ci const Combinable* fCombinable; 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci using INHERITED = GrOp; 166cb93a386Sopenharmony_ci}; 167cb93a386Sopenharmony_ci} // namespace 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci/** 170cb93a386Sopenharmony_ci * Tests adding kNumOps to an op list with all possible allowed chaining configurations. Tests 171cb93a386Sopenharmony_ci * adding the ops in all possible orders and verifies that the chained executions don't violate 172cb93a386Sopenharmony_ci * painter's order. 173cb93a386Sopenharmony_ci */ 174cb93a386Sopenharmony_ciDEF_GPUTEST(OpChainTest, reporter, /*ctxInfo*/) { 175cb93a386Sopenharmony_ci sk_sp<GrDirectContext> dContext = GrDirectContext::MakeMock(nullptr); 176cb93a386Sopenharmony_ci SkASSERT(dContext); 177cb93a386Sopenharmony_ci const GrCaps* caps = dContext->priv().caps(); 178cb93a386Sopenharmony_ci static constexpr SkISize kDims = {kNumOps + 1, 1}; 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 181cb93a386Sopenharmony_ci GrRenderable::kYes); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci static const GrSurfaceOrigin kOrigin = kTopLeft_GrSurfaceOrigin; 184cb93a386Sopenharmony_ci auto proxy = dContext->priv().proxyProvider()->createProxy( 185cb93a386Sopenharmony_ci format, kDims, GrRenderable::kYes, 1, GrMipmapped::kNo, SkBackingFit::kExact, 186cb93a386Sopenharmony_ci SkBudgeted::kNo, GrProtected::kNo, GrInternalSurfaceFlags::kNone); 187cb93a386Sopenharmony_ci SkASSERT(proxy); 188cb93a386Sopenharmony_ci proxy->instantiate(dContext->priv().resourceProvider()); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci GrSwizzle writeSwizzle = caps->getWriteSwizzle(format, GrColorType::kRGBA_8888); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci int result[result_width()]; 193cb93a386Sopenharmony_ci int validResult[result_width()]; 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci int permutation[kNumOps]; 196cb93a386Sopenharmony_ci for (int i = 0; i < kNumOps; ++i) { 197cb93a386Sopenharmony_ci permutation[i] = i; 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci // Op order permutations. 200cb93a386Sopenharmony_ci static constexpr int kNumPermutations = 100; 201cb93a386Sopenharmony_ci // For a given number of chainability groups, this is the number of random combinability reuslts 202cb93a386Sopenharmony_ci // we will test. 203cb93a386Sopenharmony_ci static constexpr int kNumCombinabilitiesPerGrouping = 20; 204cb93a386Sopenharmony_ci SkRandom random; 205cb93a386Sopenharmony_ci bool repeat = false; 206cb93a386Sopenharmony_ci Combinable combinable; 207cb93a386Sopenharmony_ci GrDrawingManager* drawingMgr = dContext->priv().drawingManager(); 208cb93a386Sopenharmony_ci sk_sp<GrArenas> arenas = sk_make_sp<GrArenas>(); 209cb93a386Sopenharmony_ci for (int p = 0; p < kNumPermutations; ++p) { 210cb93a386Sopenharmony_ci for (int i = 0; i < kNumOps - 2 && !repeat; ++i) { 211cb93a386Sopenharmony_ci // The current implementation of nextULessThan() is biased. :( 212cb93a386Sopenharmony_ci unsigned j = i + random.nextULessThan(kNumOps - i); 213cb93a386Sopenharmony_ci std::swap(permutation[i], permutation[j]); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci // g is the number of chainable groups that we partition the ops into. 216cb93a386Sopenharmony_ci for (int g = 1; g < kNumOps; ++g) { 217cb93a386Sopenharmony_ci for (int c = 0; c < kNumCombinabilitiesPerGrouping; ++c) { 218cb93a386Sopenharmony_ci init_combinable(g, &combinable, &random); 219cb93a386Sopenharmony_ci GrTokenTracker tracker; 220cb93a386Sopenharmony_ci GrOpFlushState flushState(dContext->priv().getGpu(), 221cb93a386Sopenharmony_ci dContext->priv().resourceProvider(), 222cb93a386Sopenharmony_ci &tracker); 223cb93a386Sopenharmony_ci skgpu::v1::OpsTask opsTask(drawingMgr, 224cb93a386Sopenharmony_ci GrSurfaceProxyView(proxy, kOrigin, writeSwizzle), 225cb93a386Sopenharmony_ci dContext->priv().auditTrail(), 226cb93a386Sopenharmony_ci arenas); 227cb93a386Sopenharmony_ci // This assumes the particular values of kRanges. 228cb93a386Sopenharmony_ci std::fill_n(result, result_width(), -1); 229cb93a386Sopenharmony_ci std::fill_n(validResult, result_width(), -1); 230cb93a386Sopenharmony_ci for (int i = 0; i < kNumOps; ++i) { 231cb93a386Sopenharmony_ci int value = permutation[i]; 232cb93a386Sopenharmony_ci // factor out the repeats and then use the canonical starting position and range 233cb93a386Sopenharmony_ci // to determine an actual range. 234cb93a386Sopenharmony_ci int j = value % (kNumRanges * kNumOpPositions); 235cb93a386Sopenharmony_ci int pos = j % kNumOpPositions; 236cb93a386Sopenharmony_ci Range range = kRanges[j / kNumOpPositions]; 237cb93a386Sopenharmony_ci range.fOffset += pos; 238cb93a386Sopenharmony_ci auto op = TestOp::Make(dContext.get(), value, range, result, &combinable); 239cb93a386Sopenharmony_ci TestOp* testOp = (TestOp*)op.get(); 240cb93a386Sopenharmony_ci testOp->writeResult(validResult); 241cb93a386Sopenharmony_ci opsTask.addOp(drawingMgr, std::move(op), 242cb93a386Sopenharmony_ci GrTextureResolveManager(dContext->priv().drawingManager()), 243cb93a386Sopenharmony_ci *caps); 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci opsTask.makeClosed(dContext.get()); 246cb93a386Sopenharmony_ci opsTask.prepare(&flushState); 247cb93a386Sopenharmony_ci opsTask.execute(&flushState); 248cb93a386Sopenharmony_ci opsTask.endFlush(drawingMgr); 249cb93a386Sopenharmony_ci opsTask.disown(drawingMgr); 250cb93a386Sopenharmony_ci#if 0 // Useful to repeat a random configuration that fails the test while debugger attached. 251cb93a386Sopenharmony_ci if (!std::equal(result, result + result_width(), validResult)) { 252cb93a386Sopenharmony_ci repeat = true; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci#endif 255cb93a386Sopenharmony_ci (void)repeat; 256cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, std::equal(result, result + result_width(), validResult)); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci} 261