From bc6b99d22e8d9f6543ffffdc846e40e8075046c5 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Wed, 11 Jan 2017 10:32:34 -0500 Subject: [PATCH] Add test for processor->resource ref/io counts Change-Id: I63a8cb9f1564bfc15ef98121b77946a647c79f32 Reviewed-on: https://skia-review.googlesource.com/6814 Commit-Queue: Brian Salomon Reviewed-by: Robert Phillips --- gn/tests.gni | 1 + include/gpu/GrGpuResource.h | 2 + include/gpu/GrProcessor.h | 5 + src/gpu/GrAllocator.h | 7 ++ src/gpu/GrResourceProvider.h | 1 + tests/ProcessorTest.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 249 insertions(+) create mode 100644 tests/ProcessorTest.cpp diff --git a/gn/tests.gni b/gn/tests.gni index 95e1a79..65b79ab 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -160,6 +160,7 @@ tests_sources = [ "$_tests/PointTest.cpp", "$_tests/PremulAlphaRoundTripTest.cpp", "$_tests/PrimitiveProcessorTest.cpp", + "$_tests/ProcessorTest.cpp", "$_tests/ProxyConversionTest.cpp", "$_tests/ProxyRefTest.cpp", "$_tests/ProxyTest.cpp", diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h index 29d33df..32376e5 100644 --- a/include/gpu/GrGpuResource.h +++ b/include/gpu/GrGpuResource.h @@ -75,6 +75,8 @@ public: #endif } + void testingOnly_getCounts(int* refCnt, int* readCnt, int* writeCnt) const; + protected: GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h index f0f895f..32995c3 100644 --- a/include/gpu/GrProcessor.h +++ b/include/gpu/GrProcessor.h @@ -252,6 +252,11 @@ private: */ class GrProcessor::BufferAccess : public SkNoncopyable { public: + BufferAccess() = default; + BufferAccess(GrPixelConfig texelConfig, GrBuffer* buffer, + GrShaderFlags visibility = kFragment_GrShaderFlag) { + this->reset(texelConfig, buffer, visibility); + } /** * Must be initialized before adding to a GrProcessor's buffer access list. */ diff --git a/src/gpu/GrAllocator.h b/src/gpu/GrAllocator.h index 5b9bd5b..e5d2f4e 100644 --- a/src/gpu/GrAllocator.h +++ b/src/gpu/GrAllocator.h @@ -258,6 +258,13 @@ public: return *(T*)item; } + template T& emplace_back(Args&&... args) { + void* item = fAllocator.push_back(); + SkASSERT(item); + new (item) T(std::forward(args)...); + return *(T*)item; + } + /** * Remove the last item, only call if count() != 0 */ diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index 58bd1f8..47490e1 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -89,6 +89,7 @@ public: GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*, const GrStyle&); + using GrTextureProvider::createTexture; using GrTextureProvider::assignUniqueKeyToResource; using GrTextureProvider::findAndRefResourceByUniqueKey; using GrTextureProvider::findAndRefTextureByUniqueKey; diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp new file mode 100644 index 0000000..b6caccc --- /dev/null +++ b/tests/ProcessorTest.cpp @@ -0,0 +1,233 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" +#include "Test.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "GrGpuResource.h" +#include "GrRenderTargetContext.h" +#include "GrRenderTargetContextPriv.h" +#include "GrResourceProvider.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "ops/GrTestMeshDrawOp.h" + +namespace { +class TestOp : public GrTestMeshDrawOp { +public: + DEFINE_OP_CLASS_ID + const char* name() const override { return "TestOp"; } + + static std::unique_ptr Make() { return std::unique_ptr(new TestOp); } + +private: + TestOp() : INHERITED(ClassID(), SkRect::MakeWH(100, 100), 0xFFFFFFFF) {} + + void onPrepareDraws(Target* target) const override { return; } + + typedef GrTestMeshDrawOp INHERITED; +}; + +/** + * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts + * of resources owned by child FPs. + */ +class TestFP : public GrFragmentProcessor { +public: + struct Image { + Image(sk_sp texture, GrIOType ioType) : fTexture(texture), fIOType(ioType) {} + sk_sp fTexture; + GrIOType fIOType; + }; + static sk_sp Make(sk_sp child) { + return sk_sp(new TestFP(std::move(child))); + } + static sk_sp Make(const SkTArray>& textures, + const SkTArray>& buffers, + const SkTArray& images) { + return sk_sp(new TestFP(textures, buffers, images)); + } + + const char* name() const override { return "test"; } + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { + // We don't really care about reusing these. + static int32_t gKey = 0; + b->add32(sk_atomic_inc(&gKey)); + } + + void onComputeInvariantOutput(GrInvariantOutput* inout) const override { + // We don't care about optimizing these processors. + inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); + } + +private: + TestFP(const SkTArray>& textures, const SkTArray>& buffers, + const SkTArray& images) + : fSamplers(4), fBuffers(4), fImages(4) { + for (const auto& texture : textures) { + this->addTextureSampler(&fSamplers.emplace_back(texture.get())); + } + for (const auto& buffer : buffers) { + this->addBufferAccess(&fBuffers.emplace_back(kRGBA_8888_GrPixelConfig, buffer.get())); + } + for (const Image& image : images) { + this->addImageStorageAccess(&fImages.emplace_back( + image.fTexture, image.fIOType, GrSLMemoryModel::kNone, GrSLRestrict::kNo)); + } + } + + TestFP(sk_sp child) : fSamplers(4), fBuffers(4), fImages(4) { + this->registerChildProcessor(std::move(child)); + } + + virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { + class TestGLSLFP : public GrGLSLFragmentProcessor { + public: + TestGLSLFP() {} + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); + } + + private: + }; + return new TestGLSLFP(); + } + + bool onIsEqual(const GrFragmentProcessor&) const override { return false; } + + GrTAllocator fSamplers; + GrTAllocator fBuffers; + GrTAllocator fImages; +}; +} + +template +inline void GrIORef::testingOnly_getCounts(int* refCnt, int* readCnt, int* writeCnt) const { + *refCnt = fRefCnt; + *readCnt = fPendingReads; + *writeCnt = fPendingWrites; +} + +DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) { + GrContext* context = ctxInfo.grContext(); + + GrTextureDesc desc; + desc.fConfig = kRGBA_8888_GrPixelConfig; + desc.fWidth = 10; + desc.fHeight = 10; + + for (int parentCnt = 0; parentCnt < 2; parentCnt++) { + sk_sp renderTargetContext(context->makeRenderTargetContext( + SkBackingFit::kApprox, 1, 1, kRGBA_8888_GrPixelConfig, nullptr)); + { + bool texelBufferSupport = context->caps()->shaderCaps()->texelBufferSupport(); + bool imageLoadStoreSupport = context->caps()->shaderCaps()->imageLoadStoreSupport(); + sk_sp texture1( + context->resourceProvider()->createTexture(desc, SkBudgeted::kYes)); + sk_sp texture2( + context->resourceProvider()->createTexture(desc, SkBudgeted::kYes)); + sk_sp texture3( + context->resourceProvider()->createTexture(desc, SkBudgeted::kYes)); + sk_sp texture4( + context->resourceProvider()->createTexture(desc, SkBudgeted::kYes)); + sk_sp buffer(texelBufferSupport + ? context->resourceProvider()->createBuffer( + 1024, GrBufferType::kTexel_GrBufferType, + GrAccessPattern::kStatic_GrAccessPattern, 0) + : nullptr); + { + SkTArray> textures; + SkTArray> buffers; + SkTArray images; + textures.push_back(texture1); + if (texelBufferSupport) { + buffers.push_back(buffer); + } + if (imageLoadStoreSupport) { + images.emplace_back(texture2, GrIOType::kRead_GrIOType); + images.emplace_back(texture3, GrIOType::kWrite_GrIOType); + images.emplace_back(texture4, GrIOType::kRW_GrIOType); + } + std::unique_ptr op(TestOp::Make()); + GrPaint paint; + auto fp = TestFP::Make(std::move(textures), std::move(buffers), std::move(images)); + for (int i = 0; i < parentCnt; ++i) { + fp = TestFP::Make(std::move(fp)); + } + paint.addColorFragmentProcessor(std::move(fp)); + renderTargetContext->priv().testingOnly_addDrawOp(paint, GrAAType::kNone, + std::move(op)); + } + int refCnt, readCnt, writeCnt; + + texture1->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 1 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + + if (texelBufferSupport) { + buffer->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 1 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + } + + if (imageLoadStoreSupport) { + texture2->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 1 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + + texture3->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 1 == writeCnt); + + texture4->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 1 == readCnt); + REPORTER_ASSERT(reporter, 1 == writeCnt); + } + + context->flush(); + + texture1->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + + if (texelBufferSupport) { + buffer->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + } + + if (texelBufferSupport) { + texture2->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + + texture3->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + + texture4->testingOnly_getCounts(&refCnt, &readCnt, &writeCnt); + REPORTER_ASSERT(reporter, 1 == refCnt); + REPORTER_ASSERT(reporter, 0 == readCnt); + REPORTER_ASSERT(reporter, 0 == writeCnt); + } + } + } +} +#endif -- 2.7.4