| /* |
| * Copyright 2022 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "tests/Test.h" |
| |
| #include "include/gpu/graphite/Context.h" |
| #include "include/gpu/graphite/Recorder.h" |
| #include "include/gpu/graphite/Recording.h" |
| #include "src/gpu/graphite/Buffer.h" |
| #include "src/gpu/graphite/RecorderPriv.h" |
| #include "src/gpu/graphite/UploadBufferManager.h" |
| |
| namespace skgpu::graphite { |
| |
| DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UploadBufferManagerTest, reporter, context) { |
| std::unique_ptr<Recorder> recorder = context->makeRecorder(); |
| UploadBufferManager* bufferManager = recorder->priv().uploadBufferManager(); |
| |
| // The test source data. |
| char src[8] = { |
| 1, 2, 3, 4, |
| 5, 6, 7, 8, |
| }; |
| |
| // Test multiple small writes to a reused buffer. |
| auto [smWriter0, smBufferInfo0] = bufferManager->getUploadWriter(10, 1); |
| smWriter0.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/3, /*trimRowBytes=*/3, |
| /*rowCount=*/2); |
| smWriter0.write(/*offset=*/6, src, /*srcRowBytes=*/4, /*dstRowBytes=*/2, /*trimRowBytes=*/2, |
| /*rowCount=*/2); |
| |
| auto [smWriter1, smBufferInfo1] = bufferManager->getUploadWriter(4, 1); |
| smWriter1.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/2, /*trimRowBytes=*/2, |
| /*rowCount=*/2); |
| |
| REPORTER_ASSERT(reporter, smBufferInfo0.fBuffer == smBufferInfo1.fBuffer); |
| REPORTER_ASSERT(reporter, smBufferInfo0.fOffset == 0); |
| REPORTER_ASSERT(reporter, smBufferInfo1.fOffset >= 10); |
| |
| // Test a large write, which should get its own dedicated buffer. |
| auto [lgWriter, lgBufferInfo] = bufferManager->getUploadWriter((64 << 10) + 1, 1); |
| lgWriter.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/2, /*trimRowBytes=*/2, |
| /*rowCount=*/2); |
| |
| REPORTER_ASSERT(reporter, lgBufferInfo.fBuffer != smBufferInfo0.fBuffer); |
| REPORTER_ASSERT(reporter, lgBufferInfo.fOffset == 0); |
| REPORTER_ASSERT(reporter, lgBufferInfo.fBuffer->isMapped()); |
| const void* lgBufferMap = const_cast<Buffer*>(lgBufferInfo.fBuffer)->map(); |
| const char expectedLgBufferMap[4] = { |
| 1, 2, |
| 5, 6, |
| }; |
| REPORTER_ASSERT(reporter, |
| memcmp(lgBufferMap, expectedLgBufferMap, sizeof(expectedLgBufferMap)) == 0); |
| |
| // Test another small write after the large write. |
| auto [smWriter2, smBufferInfo2] = bufferManager->getUploadWriter(2, 1); |
| smWriter2.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/2, /*trimRowBytes=*/2, |
| /*rowCount=*/1); |
| |
| REPORTER_ASSERT(reporter, smBufferInfo2.fBuffer == smBufferInfo0.fBuffer); |
| REPORTER_ASSERT(reporter, smBufferInfo2.fOffset >= 4 + smBufferInfo1.fOffset); |
| |
| REPORTER_ASSERT(reporter, smBufferInfo0.fBuffer->isMapped()); |
| const char* smBufferMap = |
| reinterpret_cast<const char*>(const_cast<Buffer*>(smBufferInfo0.fBuffer)->map()); |
| // Each section of written data could be offset and aligned by GPU-required rules, so we can't |
| // easily validate the contents of the buffer in one go, and instead test at each of the three |
| // reported offsets. |
| const char expectedSmBuffer0[10] = { 1, 2, 3, 5, 6, 7, 1, 2, 5, 6 }; |
| const char expectedSmBuffer1[4] = { 1, 2, 5, 6 }; |
| const char expectedSmBuffer2[2] = { 1, 2}; |
| REPORTER_ASSERT(reporter, memcmp(smBufferMap + smBufferInfo0.fOffset, |
| expectedSmBuffer0, |
| sizeof(expectedSmBuffer0)) == 0); |
| REPORTER_ASSERT(reporter, memcmp(smBufferMap + smBufferInfo1.fOffset, |
| expectedSmBuffer1, |
| sizeof(expectedSmBuffer1)) == 0); |
| REPORTER_ASSERT(reporter, memcmp(smBufferMap + smBufferInfo2.fOffset, |
| expectedSmBuffer1, |
| sizeof(expectedSmBuffer2)) == 0); |
| |
| // Snap a Recording from the Recorder. This will transfer resources from the UploadBufferManager |
| // to the Recording. |
| auto recording = recorder->snap(); |
| |
| // Test writes with a required alignment. |
| auto [alWriter0, alBufferInfo0] = bufferManager->getUploadWriter(6, 4); |
| alWriter0.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/3, /*trimRowBytes=*/3, |
| /*rowCount=*/2); |
| |
| auto [alWriter1, alBufferInfo1] = bufferManager->getUploadWriter(2, 4); |
| alWriter1.write(/*offset=*/0, src, /*srcRowBytes=*/4, /*dstRowBytes=*/2, /*trimRowBytes=*/2, |
| /*rowCount=*/1); |
| |
| // Should not share a buffer with earlier small writes, since we've transferred previously- |
| // allocated resources to the command buffer. |
| REPORTER_ASSERT(reporter, alBufferInfo0.fBuffer != smBufferInfo0.fBuffer); |
| REPORTER_ASSERT(reporter, alBufferInfo0.fBuffer == alBufferInfo1.fBuffer); |
| REPORTER_ASSERT(reporter, alBufferInfo0.fOffset == 0); |
| REPORTER_ASSERT(reporter, alBufferInfo1.fOffset == 8); |
| |
| // From alWriter0. |
| const char expectedAlBufferMap0[6] = { |
| 1, 2, 3, |
| 5, 6, 7, |
| }; |
| // From alWriter1. |
| const char expectedAlBufferMap1[2] = { |
| 1, 2, |
| }; |
| |
| REPORTER_ASSERT(reporter, alBufferInfo0.fBuffer->isMapped()); |
| const void* alBufferMap = const_cast<Buffer*>(alBufferInfo0.fBuffer)->map(); |
| REPORTER_ASSERT(reporter, |
| memcmp(alBufferMap, expectedAlBufferMap0, sizeof(expectedAlBufferMap0)) == 0); |
| |
| alBufferMap = SkTAddOffset<const void>(alBufferMap, 8); |
| REPORTER_ASSERT(reporter, |
| memcmp(alBufferMap, expectedAlBufferMap1, sizeof(expectedAlBufferMap1)) == 0); |
| } |
| |
| } // namespace skgpu::graphite |