00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef NVBLASTTKEVENTQUEUE_H
00030 #define NVBLASTTKEVENTQUEUE_H
00031
00032 #include <algorithm>
00033 #include <vector>
00034
00035 #include <mutex>
00036 #include <atomic>
00037
00038 #include "NvBlastTkFrameworkImpl.h"
00039 #include "NvBlastAssert.h"
00040
00041
00042 namespace Nv {
00043 namespace Blast {
00044
00061 class TkEventQueue
00062 {
00063 public:
00064 TkEventQueue() : m_currentEvent(0), m_poolCapacity(0), m_pool(nullptr), m_allowAllocs(true) {}
00065
00070 operator const Array<TkEvent>::type&()
00071 {
00072 NVBLAST_ASSERT(m_allowAllocs);
00073 NVBLAST_ASSERT(m_currentEvent == m_events.size());
00074 return m_events;
00075 }
00076
00084 void protect(bool enable)
00085 {
00086
00087
00088 NVBLAST_ASSERT(m_currentEvent <= m_events.capacity());
00089 m_events.resizeUninitialized(m_currentEvent);
00090 m_allowAllocs = !enable;
00091 }
00092
00097 void reset()
00098 {
00099 m_events.clear();
00100 m_currentEvent = 0;
00101 for (void* mem : m_memory)
00102 {
00103 NVBLAST_FREE(mem);
00104 }
00105 m_memory.clear();
00106 m_currentData = 0;
00107 m_allowAllocs = true;
00108 m_poolCapacity = 0;
00109 m_pool = nullptr;
00110 }
00111
00115 template<class T>
00116 void addEvent(T* payload)
00117 {
00118 uint32_t index = m_currentEvent.fetch_add(1);
00119
00120
00121 NVBLAST_ASSERT(m_allowAllocs || m_currentEvent <= m_events.capacity());
00122
00123 m_events.resizeUninitialized(m_currentEvent);
00124
00125
00126
00127 NVBLAST_ASSERT(!m_allowAllocs || m_currentEvent == m_events.size());
00128
00129 TkEvent& evt = m_events[index];
00130 evt.type = TkEvent::Type(T::EVENT_TYPE);
00131 evt.payload = payload;
00132 }
00133
00137 template<typename T>
00138 T* allocData()
00139 {
00140 uint32_t index = m_currentData.fetch_add(sizeof(T));
00141 if (m_currentData <= m_poolCapacity)
00142 {
00143 return reinterpret_cast<T*>(&m_pool[index]);
00144 }
00145 else
00146 {
00147
00148 reserveData(sizeof(T));
00149
00150 m_currentData = sizeof(T);
00151 return reinterpret_cast<T*>(&m_pool[0]);
00152 }
00153 }
00154
00160 void reserveData(size_t size)
00161 {
00162 NVBLAST_ASSERT(m_allowAllocs);
00163 m_pool = reinterpret_cast<uint8_t*>(allocDataBySize(size));
00164 m_poolCapacity = size;
00165 m_currentData = 0;
00166 }
00167
00171 void reserveEvents(uint32_t n)
00172 {
00173 NVBLAST_ASSERT(m_allowAllocs);
00174 m_events.reserve(m_events.size() + n);
00175 }
00176
00180 void addListener(TkEventListener& l)
00181 {
00182 m_listeners.pushBack(&l);
00183 }
00184
00188 void removeListener(TkEventListener& l)
00189 {
00190 m_listeners.findAndReplaceWithLast(&l);
00191 }
00192
00197 void dispatch()
00198 {
00199 dispatch(*this);
00200 reset();
00201 }
00202
00206 void dispatch(const Array<TkEvent>::type& events) const
00207 {
00208 if (events.size())
00209 {
00210 for (TkEventListener* l : m_listeners)
00211 {
00212 BLAST_PROFILE_SCOPE_M("TkEventQueue::dispatch");
00213 l->receive(events.begin(), events.size());
00214 }
00215 }
00216 }
00217
00218 private:
00222 void* allocDataBySize(size_t size)
00223 {
00224 void* memory = nullptr;
00225 if (size > 0)
00226 {
00227 memory = NVBLAST_ALLOC_NAMED(size, "TkEventQueue Data");
00228 m_memory.pushBack(memory);
00229 }
00230 return memory;
00231 }
00232
00233
00234 Array<TkEvent>::type m_events;
00235 Array<void*>::type m_memory;
00236 std::atomic<uint32_t> m_currentEvent;
00237 std::atomic<uint32_t> m_currentData;
00238 size_t m_poolCapacity;
00239 uint8_t* m_pool;
00240 bool m_allowAllocs;
00241 InlineArray<TkEventListener*,4>::type m_listeners;
00242 };
00243
00244 }
00245 }
00246
00247
00248 #endif // ifndef NVBLASTTKEVENTQUEUE_H