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/BsVertexBuffer.h"
4#include "Managers/BsHardwareBufferManager.h"
5#include "Profiling/BsRenderStats.h"
6#include "RenderAPI/BsGpuBuffer.h"
7
8namespace bs
9{
10 void checkValidDesc(const VERTEX_BUFFER_DESC& desc)
11 {
12 if(desc.vertexSize == 0)
13 BS_EXCEPT(InvalidParametersException, "Vertex buffer vertex size is not allowed to be zero.");
14
15 if(desc.numVerts == 0)
16 BS_EXCEPT(InvalidParametersException, "Vertex buffer vertex count is not allowed to be zero.");
17 }
18
19 VertexBufferProperties::VertexBufferProperties(UINT32 numVertices, UINT32 vertexSize)
20 :mNumVertices(numVertices), mVertexSize(vertexSize)
21 { }
22
23 VertexBuffer::VertexBuffer(const VERTEX_BUFFER_DESC& desc)
24 : mProperties(desc.numVerts, desc.vertexSize), mUsage(desc.usage), mStreamOut(desc.streamOut)
25 {
26#if BS_DEBUG_MODE
27 checkValidDesc(desc);
28#endif
29 }
30
31 SPtr<ct::CoreObject> VertexBuffer::createCore() const
32 {
33 VERTEX_BUFFER_DESC desc;
34 desc.vertexSize = mProperties.mVertexSize;
35 desc.numVerts = mProperties.mNumVertices;
36 desc.usage = mUsage;
37 desc.streamOut = mStreamOut;
38
39 return ct::HardwareBufferManager::instance().createVertexBufferInternal(desc);
40 }
41
42 SPtr<ct::VertexBuffer> VertexBuffer::getCore() const
43 {
44 return std::static_pointer_cast<ct::VertexBuffer>(mCoreSpecific);
45 }
46
47 SPtr<VertexBuffer> VertexBuffer::create(const VERTEX_BUFFER_DESC& desc)
48 {
49 return HardwareBufferManager::instance().createVertexBuffer(desc);
50 }
51
52 namespace ct
53 {
54 VertexBuffer::VertexBuffer(const VERTEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
55 :HardwareBuffer(desc.vertexSize * desc.numVerts, desc.usage, deviceMask), mProperties(desc.numVerts, desc.vertexSize)
56 {
57#if BS_DEBUG_MODE
58 checkValidDesc(desc);
59#endif
60 }
61
62 VertexBuffer::~VertexBuffer()
63 {
64 if(mBuffer && !mSharedBuffer)
65 mBufferDeleter(mBuffer);
66
67 BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexBuffer);
68 }
69
70 void VertexBuffer::initialize()
71 {
72 BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
73 CoreObject::initialize();
74 }
75
76 void* VertexBuffer::map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx)
77 {
78#if BS_PROFILING_ENABLED
79 if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
80 {
81 BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
82 }
83
84 if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
85 {
86 BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
87 }
88#endif
89
90 return mBuffer->lock(offset, length, options, deviceIdx, queueIdx);
91 }
92
93 void VertexBuffer::unmap()
94 {
95 mBuffer->unlock();
96 }
97
98 void VertexBuffer::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx)
99 {
100 mBuffer->readData(offset, length, dest, deviceIdx, queueIdx);
101 BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
102 }
103
104 void VertexBuffer::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags,
105 UINT32 queueIdx)
106 {
107 mBuffer->writeData(offset, length, source, writeFlags, queueIdx);
108 BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
109 }
110
111 void VertexBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset,
112 UINT32 dstOffset, UINT32 length, bool discardWholeBuffer, const SPtr<CommandBuffer>& commandBuffer)
113 {
114 auto& srcVertexBuffer = static_cast<VertexBuffer&>(srcBuffer);
115 mBuffer->copyData(*srcVertexBuffer.mBuffer, srcOffset, dstOffset, length, discardWholeBuffer, commandBuffer);
116 }
117
118 SPtr<GpuBuffer> VertexBuffer::getLoadStore(GpuBufferType type, GpuBufferFormat format, UINT32 elementSize)
119 {
120 if((mUsage & GBU_LOADSTORE) != GBU_LOADSTORE)
121 return nullptr;
122
123 for(const auto& entry : mLoadStoreViews)
124 {
125 const GpuBufferProperties& props = entry->getProperties();
126 if(props.getType() == type)
127 {
128 if(type == GBT_STANDARD && props.getFormat() == format)
129 return entry;
130
131 if(type == GBT_STRUCTURED && props.getElementSize() == elementSize)
132 return entry;
133 }
134 }
135
136 UINT32 elemSize = type == GBT_STANDARD ? bs::GpuBuffer::getFormatSize(format) : elementSize;
137 if((mBuffer->getSize() % elemSize) != 0)
138 {
139 LOGERR("Size of the buffer isn't divisible by individual element size provided for the buffer view.");
140 return nullptr;
141 }
142
143 GPU_BUFFER_DESC desc;
144 desc.type = type;
145 desc.format = format;
146 desc.usage = mUsage;
147 desc.elementSize = elementSize;
148 desc.elementCount = mBuffer->getSize() / elemSize;
149
150 if(!mSharedBuffer)
151 mSharedBuffer = bs_shared_ptr(mBuffer, mBufferDeleter);
152
153 SPtr<GpuBuffer> newView = GpuBuffer::create(desc, mSharedBuffer);
154 mLoadStoreViews.push_back(newView);
155
156 return newView;
157 }
158
159 SPtr<VertexBuffer> VertexBuffer::create(const VERTEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
160 {
161 return HardwareBufferManager::instance().createVertexBuffer(desc, deviceMask);
162 }
163 }
164}
165