1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "RenderAPI/BsGpuBuffer.h" |
4 | #include "Error/BsException.h" |
5 | #include "RenderAPI/BsRenderAPI.h" |
6 | #include "Managers/BsHardwareBufferManager.h" |
7 | #include "Profiling/BsRenderStats.h" |
8 | |
9 | namespace bs |
10 | { |
11 | UINT32 getBufferSize(const GPU_BUFFER_DESC& desc) |
12 | { |
13 | UINT32 elementSize; |
14 | |
15 | if (desc.type == GBT_STANDARD) |
16 | elementSize = GpuBuffer::getFormatSize(desc.format); |
17 | else |
18 | elementSize = desc.elementSize; |
19 | |
20 | return elementSize * desc.elementCount; |
21 | } |
22 | |
23 | GpuBufferProperties::GpuBufferProperties(const GPU_BUFFER_DESC& desc) |
24 | : mDesc(desc) |
25 | { |
26 | if(mDesc.type == GBT_STANDARD) |
27 | mDesc.elementSize = GpuBuffer::getFormatSize(mDesc.format); |
28 | } |
29 | |
30 | GpuBuffer::GpuBuffer(const GPU_BUFFER_DESC& desc) |
31 | :mProperties(desc) |
32 | { |
33 | } |
34 | |
35 | SPtr<ct::GpuBuffer> GpuBuffer::getCore() const |
36 | { |
37 | return std::static_pointer_cast<ct::GpuBuffer>(mCoreSpecific); |
38 | } |
39 | |
40 | SPtr<ct::CoreObject> GpuBuffer::createCore() const |
41 | { |
42 | return ct::HardwareBufferManager::instance().createGpuBufferInternal(mProperties.mDesc); |
43 | } |
44 | |
45 | UINT32 GpuBuffer::getFormatSize(GpuBufferFormat format) |
46 | { |
47 | static bool lookupInitialized = false; |
48 | |
49 | static UINT32 lookup[BF_COUNT]; |
50 | if (!lookupInitialized) |
51 | { |
52 | lookup[BF_16X1F] = 2; |
53 | lookup[BF_16X2F] = 4; |
54 | lookup[BF_16X4F] = 8; |
55 | lookup[BF_32X1F] = 4; |
56 | lookup[BF_32X2F] = 8; |
57 | lookup[BF_32X3F] = 12; |
58 | lookup[BF_32X4F] = 16; |
59 | lookup[BF_8X1] = 1; |
60 | lookup[BF_8X2] = 2; |
61 | lookup[BF_8X4] = 4; |
62 | lookup[BF_16X1] = 2; |
63 | lookup[BF_16X2] = 4; |
64 | lookup[BF_16X4] = 8; |
65 | lookup[BF_8X1S] = 1; |
66 | lookup[BF_8X2S] = 2; |
67 | lookup[BF_8X4S] = 4; |
68 | lookup[BF_16X1S] = 2; |
69 | lookup[BF_16X2S] = 4; |
70 | lookup[BF_16X4S] = 8; |
71 | lookup[BF_32X1S] = 4; |
72 | lookup[BF_32X2S] = 8; |
73 | lookup[BF_32X3S] = 12; |
74 | lookup[BF_32X4S] = 16; |
75 | lookup[BF_8X1U] = 1; |
76 | lookup[BF_8X2U] = 2; |
77 | lookup[BF_8X4U] = 4; |
78 | lookup[BF_16X1U] = 2; |
79 | lookup[BF_16X2U] = 4; |
80 | lookup[BF_16X4U] = 8; |
81 | lookup[BF_32X1U] = 4; |
82 | lookup[BF_32X2U] = 8; |
83 | lookup[BF_32X3U] = 12; |
84 | lookup[BF_32X4U] = 16; |
85 | |
86 | lookupInitialized = true; |
87 | } |
88 | |
89 | if (format >= BF_COUNT) |
90 | return 0; |
91 | |
92 | return lookup[(UINT32)format]; |
93 | } |
94 | |
95 | SPtr<GpuBuffer> GpuBuffer::create(const GPU_BUFFER_DESC& desc) |
96 | { |
97 | return HardwareBufferManager::instance().createGpuBuffer(desc); |
98 | } |
99 | |
100 | namespace ct |
101 | { |
102 | GpuBuffer::GpuBuffer(const GPU_BUFFER_DESC& desc, GpuDeviceFlags deviceMask) |
103 | :HardwareBuffer(getBufferSize(desc), desc.usage, deviceMask), mProperties(desc) |
104 | { |
105 | if (desc.type != GBT_STANDARD) |
106 | assert(desc.format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers" ); |
107 | else |
108 | assert(desc.elementSize == 0 && "No element size can be provided for standard buffer. Size is determined from format." ); |
109 | } |
110 | |
111 | GpuBuffer::GpuBuffer(const GPU_BUFFER_DESC& desc, SPtr<HardwareBuffer> underlyingBuffer) |
112 | : HardwareBuffer(getBufferSize(desc), desc.usage, underlyingBuffer->getDeviceMask()), mProperties(desc) |
113 | , mBuffer(underlyingBuffer.get()), mSharedBuffer(std::move(underlyingBuffer)), mIsExternalBuffer(true) |
114 | { |
115 | const auto& props = getProperties(); |
116 | assert(mSharedBuffer->getSize() == (props.getElementCount() * props.getElementSize())); |
117 | |
118 | if (desc.type != GBT_STANDARD) |
119 | assert(desc.format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers" ); |
120 | else |
121 | assert(desc.elementSize == 0 && "No element size can be provided for standard buffer. Size is determined from format." ); |
122 | } |
123 | |
124 | GpuBuffer::~GpuBuffer() |
125 | { |
126 | BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuBuffer); |
127 | |
128 | if(mBuffer && !mSharedBuffer) |
129 | mBufferDeleter(mBuffer); |
130 | } |
131 | |
132 | void GpuBuffer::initialize() |
133 | { |
134 | BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer); |
135 | CoreObject::initialize(); |
136 | } |
137 | |
138 | void* GpuBuffer::map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx) |
139 | { |
140 | #if BS_PROFILING_ENABLED |
141 | if (options == GBL_READ_ONLY || options == GBL_READ_WRITE) |
142 | { |
143 | BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer); |
144 | } |
145 | |
146 | if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE) |
147 | { |
148 | BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer); |
149 | } |
150 | #endif |
151 | |
152 | return mBuffer->lock(offset, length, options, deviceIdx, queueIdx); |
153 | } |
154 | |
155 | void GpuBuffer::unmap() |
156 | { |
157 | mBuffer->unlock(); |
158 | } |
159 | |
160 | void GpuBuffer::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx) |
161 | { |
162 | BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer); |
163 | |
164 | mBuffer->readData(offset, length, dest, deviceIdx, queueIdx); |
165 | } |
166 | |
167 | void GpuBuffer::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags, |
168 | UINT32 queueIdx) |
169 | { |
170 | BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer); |
171 | |
172 | mBuffer->writeData(offset, length, source, writeFlags, queueIdx); |
173 | } |
174 | |
175 | void GpuBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, UINT32 length, |
176 | bool discardWholeBuffer, const SPtr<CommandBuffer>& commandBuffer) |
177 | { |
178 | auto& srcGpuBuffer = static_cast<GpuBuffer&>(srcBuffer); |
179 | mBuffer->copyData(*srcGpuBuffer.mBuffer, srcOffset, dstOffset, length, discardWholeBuffer, commandBuffer); |
180 | } |
181 | |
182 | SPtr<GpuBuffer> GpuBuffer::getView(GpuBufferType type, GpuBufferFormat format, UINT32 elementSize) |
183 | { |
184 | const UINT32 elemSize = type == GBT_STANDARD ? bs::GpuBuffer::getFormatSize(format) : elementSize; |
185 | if((mBuffer->getSize() % elemSize) != 0) |
186 | { |
187 | LOGERR("Size of the buffer isn't divisible by individual element size provided for the buffer view." ); |
188 | return nullptr; |
189 | } |
190 | |
191 | GPU_BUFFER_DESC desc; |
192 | desc.type = type; |
193 | desc.format = format; |
194 | desc.usage = mUsage; |
195 | desc.elementSize = elementSize; |
196 | desc.elementCount = mBuffer->getSize() / elemSize; |
197 | |
198 | if(!mSharedBuffer) |
199 | { |
200 | mSharedBuffer = bs_shared_ptr(mBuffer, mBufferDeleter); |
201 | mIsExternalBuffer = false; |
202 | } |
203 | |
204 | SPtr<GpuBuffer> newView = create(desc, mSharedBuffer); |
205 | return newView; |
206 | } |
207 | |
208 | SPtr<GpuBuffer> GpuBuffer::create(const GPU_BUFFER_DESC& desc, GpuDeviceFlags deviceMask) |
209 | { |
210 | return HardwareBufferManager::instance().createGpuBuffer(desc, deviceMask); |
211 | } |
212 | |
213 | SPtr<GpuBuffer> GpuBuffer::create(const GPU_BUFFER_DESC& desc, SPtr<HardwareBuffer> underlyingBuffer) |
214 | { |
215 | return HardwareBufferManager::instance().createGpuBuffer(desc, std::move(underlyingBuffer)); |
216 | } |
217 | } |
218 | } |
219 | |