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
9namespace 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