| 77 | } |
| 78 | |
| 79 | ref<Buffer> BufferAllocator::getGPUBuffer(ref<Device> pDevice) |
| 80 | { |
| 81 | if (mBuffer.empty()) |
| 82 | { |
| 83 | // If there is no allocated data, we don't need a GPU buffer and return nullptr. |
| 84 | return nullptr; |
| 85 | } |
| 86 | |
| 87 | // Compute required size of the buffer on the GPU including padding and allocate |
| 88 | // buffer of the right type (structured or raw buffer). |
| 89 | size_t elemSize = mElementSize > 0 ? mElementSize : 4ull; |
| 90 | size_t bufSize = align_to(elemSize, mBuffer.size()); |
| 91 | |
| 92 | if (mpGpuBuffer == nullptr || mpGpuBuffer->getSize() < bufSize) |
| 93 | { |
| 94 | if (mElementSize > 0) |
| 95 | { |
| 96 | size_t elemCount = bufSize / mElementSize; |
| 97 | FALCOR_ASSERT(elemCount * mElementSize == bufSize); |
| 98 | mpGpuBuffer = pDevice->createStructuredBuffer( |
| 99 | mElementSize, elemCount, mBindFlags, MemoryType::DeviceLocal, nullptr, false /* no UAV counter */ |
| 100 | ); |
| 101 | } |
| 102 | else |
| 103 | { |
| 104 | mpGpuBuffer = pDevice->createBuffer(bufSize, mBindFlags, MemoryType::DeviceLocal, nullptr); |
| 105 | } |
| 106 | |
| 107 | mDirty = Range(0, mBuffer.size()); // Mark entire buffer as dirty so the data gets uploaded. |
| 108 | } |
| 109 | |
| 110 | // If any range is dirty, upload the data from the CPU to the GPU. |
| 111 | if (mDirty.start < mDirty.end) |
| 112 | { |
| 113 | size_t byteSize = mDirty.end - mDirty.start; |
| 114 | size_t byteOffset = mDirty.start; |
| 115 | FALCOR_ASSERT(byteOffset + byteSize <= mBuffer.size()); |
| 116 | FALCOR_ASSERT(mBuffer.size() <= mpGpuBuffer->getSize()); |
| 117 | mpGpuBuffer->setBlob(mBuffer.data() + byteOffset, byteOffset, byteSize); |
| 118 | |
| 119 | mDirty = {mBuffer.size(), 0}; // Reset dirty range to inverted range. Any min/max operation on it will work. |
| 120 | } |
| 121 | |
| 122 | return mpGpuBuffer; |
| 123 | } |
| 124 | |
| 125 | // Private |
| 126 | |