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