/src/skia/src/gpu/GrRingBuffer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2020 Google LLC |
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 | | |
8 | | #include "src/gpu/GrRingBuffer.h" |
9 | | |
10 | | #include "src/gpu/GrDirectContextPriv.h" |
11 | | #include "src/gpu/GrGpu.h" |
12 | | #include "src/gpu/GrResourceProvider.h" |
13 | | |
14 | | // Get offset into buffer that has enough space for size |
15 | | // Returns fTotalSize if no space |
16 | 0 | size_t GrRingBuffer::getAllocationOffset(size_t size) { |
17 | | // capture current state locally (because fTail could be overwritten by the completion handler) |
18 | 0 | size_t head, tail; |
19 | 0 | head = fHead; |
20 | 0 | tail = fTail; |
21 | | |
22 | | // The head and tail indices increment without bound, wrapping with overflow, |
23 | | // so we need to mod them down to the actual bounds of the allocation to determine |
24 | | // which blocks are available. |
25 | 0 | size_t modHead = head & (fTotalSize - 1); |
26 | 0 | size_t modTail = tail & (fTotalSize - 1); |
27 | |
|
28 | 0 | bool full = (head != tail && modHead == modTail); |
29 | |
|
30 | 0 | if (full) { |
31 | 0 | return fTotalSize; |
32 | 0 | } |
33 | | |
34 | | // case 1: free space lies at the beginning and/or the end of the buffer |
35 | 0 | if (modHead >= modTail) { |
36 | | // check for room at the end |
37 | 0 | if (fTotalSize - modHead < size) { |
38 | | // no room at the end, check the beginning |
39 | 0 | if (modTail < size) { |
40 | | // no room at the beginning |
41 | 0 | return fTotalSize; |
42 | 0 | } |
43 | | // we are going to allocate from the beginning, adjust head to '0' position |
44 | 0 | head += fTotalSize - modHead; |
45 | 0 | modHead = 0; |
46 | 0 | } |
47 | | // case 2: free space lies in the middle of the buffer, check for room there |
48 | 0 | } else if (modTail - modHead < size) { |
49 | | // no room in the middle |
50 | 0 | return fTotalSize; |
51 | 0 | } |
52 | | |
53 | 0 | fHead = GrAlignTo(head + size, fAlignment); |
54 | 0 | return modHead; |
55 | 0 | } |
56 | | |
57 | 0 | GrRingBuffer::Slice GrRingBuffer::suballocate(size_t size) { |
58 | 0 | fNewAllocation = true; |
59 | 0 | if (fCurrentBuffer) { |
60 | 0 | size_t offset = this->getAllocationOffset(size); |
61 | 0 | if (offset < fTotalSize) { |
62 | 0 | return { fCurrentBuffer.get(), offset }; |
63 | 0 | } |
64 | | |
65 | | // Try to grow allocation (old allocation will age out). |
66 | 0 | fTotalSize *= 2; |
67 | | // Add current buffer to be tracked for next submit. |
68 | 0 | fPreviousBuffers.push_back(std::move(fCurrentBuffer)); |
69 | 0 | } |
70 | |
|
71 | 0 | GrResourceProvider* resourceProvider = fGpu->getContext()->priv().resourceProvider(); |
72 | 0 | fCurrentBuffer = resourceProvider->createBuffer(fTotalSize, fType, kDynamic_GrAccessPattern); |
73 | |
|
74 | 0 | SkASSERT(fCurrentBuffer); |
75 | 0 | fHead = 0; |
76 | 0 | fTail = 0; |
77 | 0 | fGenID++; |
78 | 0 | size_t offset = this->getAllocationOffset(size); |
79 | 0 | SkASSERT(offset < fTotalSize); |
80 | 0 | return { fCurrentBuffer.get(), offset }; |
81 | 0 | } Unexecuted instantiation: GrRingBuffer::suballocate(unsigned long) Unexecuted instantiation: GrRingBuffer::suballocate(unsigned long) |
82 | | |
83 | | // used when current command buffer/command list is submitted |
84 | 0 | void GrRingBuffer::startSubmit(GrGpu* gpu) { |
85 | 0 | for (unsigned int i = 0; i < fPreviousBuffers.size(); ++i) { |
86 | 0 | fPreviousBuffers[i]->unmap(); |
87 | 0 | gpu->takeOwnershipOfBuffer(std::move(fPreviousBuffers[i])); |
88 | 0 | } |
89 | 0 | fPreviousBuffers.clear(); |
90 | |
|
91 | 0 | if (fNewAllocation) { |
92 | | #ifdef SK_BUILD_FOR_MAC |
93 | | // Since we're using a Managed buffer on MacOS we need to unmap to write back to GPU |
94 | | // TODO: once we set up persistently mapped UPLOAD buffers on D3D, we can remove the |
95 | | // platform restriction. |
96 | | fCurrentBuffer->unmap(); |
97 | | #endif |
98 | 0 | SubmitData* submitData = new SubmitData(); |
99 | 0 | submitData->fOwner = this; |
100 | 0 | submitData->fLastHead = fHead; |
101 | 0 | submitData->fGenID = fGenID; |
102 | 0 | gpu->addFinishedProc(FinishSubmit, submitData); |
103 | 0 | fNewAllocation = false; |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | // used when current command buffer/command list is completed |
108 | 0 | void GrRingBuffer::FinishSubmit(void* finishedContext) { |
109 | 0 | GrRingBuffer::SubmitData* submitData = (GrRingBuffer::SubmitData*)finishedContext; |
110 | 0 | if (submitData && submitData->fOwner && submitData->fGenID == submitData->fOwner->fGenID) { |
111 | 0 | submitData->fOwner->fTail = submitData->fLastHead; |
112 | 0 | submitData->fOwner = nullptr; |
113 | 0 | } |
114 | 0 | delete submitData; |
115 | 0 | } |