1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "default.h"
7#include "device.h"
8
9namespace embree
10{
11 /*! Implements an API data buffer object. This class may or may not own the data. */
12 class Buffer : public RefCount
13 {
14 public:
15 /*! Buffer construction */
16 Buffer()
17 : device(nullptr), ptr(nullptr), numBytes(0), shared(false) {}
18
19 /*! Buffer construction */
20 Buffer(Device* device, size_t numBytes_in, void* ptr_in = nullptr)
21 : device(device), numBytes(numBytes_in)
22 {
23 device->refInc();
24
25 if (ptr_in)
26 {
27 shared = true;
28 ptr = (char*)ptr_in;
29 }
30 else
31 {
32 shared = false;
33 alloc();
34 }
35 }
36
37 /*! Buffer destruction */
38 ~Buffer() {
39 free();
40 device->refDec();
41 }
42
43 /*! this class is not copyable */
44 private:
45 Buffer(const Buffer& other) DELETED; // do not implement
46 Buffer& operator =(const Buffer& other) DELETED; // do not implement
47
48 public:
49 /* inits and allocates the buffer */
50 void create(Device* device_in, size_t numBytes_in)
51 {
52 init(device_in, numBytes_in);
53 alloc();
54 }
55
56 /* inits the buffer */
57 void init(Device* device_in, size_t numBytes_in)
58 {
59 free();
60 device = device_in;
61 ptr = nullptr;
62 numBytes = numBytes_in;
63 shared = false;
64 }
65
66 /*! sets shared buffer */
67 void set(Device* device_in, void* ptr_in, size_t numBytes_in)
68 {
69 free();
70 device = device_in;
71 ptr = (char*)ptr_in;
72 if (numBytes_in != (size_t)-1)
73 numBytes = numBytes_in;
74 shared = true;
75 }
76
77 /*! allocated buffer */
78 void alloc()
79 {
80 if (device)
81 device->memoryMonitor(this->bytes(), false);
82 size_t b = (this->bytes()+15) & ssize_t(-16);
83 ptr = (char*)alignedMalloc(b,16);
84 }
85
86 /*! frees the buffer */
87 void free()
88 {
89 if (shared) return;
90 alignedFree(ptr);
91 if (device)
92 device->memoryMonitor(-ssize_t(this->bytes()), true);
93 ptr = nullptr;
94 }
95
96 /*! gets buffer pointer */
97 void* data()
98 {
99 /* report error if buffer is not existing */
100 if (!device)
101 throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer specified");
102
103 /* return buffer */
104 return ptr;
105 }
106
107 /*! returns pointer to first element */
108 __forceinline char* getPtr() const {
109 return ptr;
110 }
111
112 /*! returns the number of bytes of the buffer */
113 __forceinline size_t bytes() const {
114 return numBytes;
115 }
116
117 /*! returns true of the buffer is not empty */
118 __forceinline operator bool() const {
119 return ptr;
120 }
121
122 public:
123 Device* device; //!< device to report memory usage to
124 char* ptr; //!< pointer to buffer data
125 size_t numBytes; //!< number of bytes in the buffer
126 bool shared; //!< set if memory is shared with application
127 };
128
129 /*! An untyped contiguous range of a buffer. This class does not own the buffer content. */
130 class RawBufferView
131 {
132 public:
133 /*! Buffer construction */
134 RawBufferView()
135 : ptr_ofs(nullptr), stride(0), num(0), format(RTC_FORMAT_UNDEFINED), modCounter(1), modified(true), userData(0) {}
136
137 public:
138 /*! sets the buffer view */
139 void set(const Ref<Buffer>& buffer_in, size_t offset_in, size_t stride_in, size_t num_in, RTCFormat format_in)
140 {
141 if ((offset_in + stride_in * num_in) > (stride_in * buffer_in->numBytes))
142 throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "buffer range out of bounds");
143
144 ptr_ofs = buffer_in->ptr + offset_in;
145 stride = stride_in;
146 num = num_in;
147 format = format_in;
148 modCounter++;
149 modified = true;
150 buffer = buffer_in;
151 }
152
153 /*! returns pointer to the first element */
154 __forceinline char* getPtr() const {
155 return ptr_ofs;
156 }
157
158 /*! returns pointer to the i'th element */
159 __forceinline char* getPtr(size_t i) const
160 {
161 assert(i<num);
162 return ptr_ofs + i*stride;
163 }
164
165 /*! returns the number of elements of the buffer */
166 __forceinline size_t size() const {
167 return num;
168 }
169
170 /*! returns the number of bytes of the buffer */
171 __forceinline size_t bytes() const {
172 return num*stride;
173 }
174
175 /*! returns the buffer stride */
176 __forceinline unsigned getStride() const
177 {
178 assert(stride <= unsigned(inf));
179 return unsigned(stride);
180 }
181
182 /*! return the buffer format */
183 __forceinline RTCFormat getFormat() const {
184 return format;
185 }
186
187 /*! mark buffer as modified or unmodified */
188 __forceinline void setModified() {
189 modCounter++;
190 modified = true;
191 }
192
193 /*! mark buffer as modified or unmodified */
194 __forceinline bool isModified(unsigned int otherModCounter) const {
195 return modCounter > otherModCounter;
196 }
197
198 /*! mark buffer as modified or unmodified */
199 __forceinline bool isLocalModified() const {
200 return modified;
201 }
202
203 /*! clear local modified flag */
204 __forceinline void clearLocalModified() {
205 modified = false;
206 }
207
208 /*! returns true of the buffer is not empty */
209 __forceinline operator bool() const {
210 return ptr_ofs;
211 }
212
213 /*! checks padding to 16 byte check, fails hard */
214 __forceinline void checkPadding16() const
215 {
216 if (ptr_ofs && num)
217 volatile int MAYBE_UNUSED w = *((int*)getPtr(size()-1)+3); // FIXME: is failing hard avoidable?
218 }
219
220 public:
221 char* ptr_ofs; //!< base pointer plus offset
222 size_t stride; //!< stride of the buffer in bytes
223 size_t num; //!< number of elements in the buffer
224 RTCFormat format; //!< format of the buffer
225 unsigned int modCounter; //!< version ID of this buffer
226 bool modified; //!< local modified data
227 int userData; //!< special data
228 Ref<Buffer> buffer; //!< reference to the parent buffer
229 };
230
231 /*! A typed contiguous range of a buffer. This class does not own the buffer content. */
232 template<typename T>
233 class BufferView : public RawBufferView
234 {
235 public:
236 typedef T value_type;
237
238 /*! access to the ith element of the buffer */
239 __forceinline T& operator [](size_t i) { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
240 __forceinline const T& operator [](size_t i) const { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
241 };
242
243 template<>
244 class BufferView<Vec3fa> : public RawBufferView
245 {
246 public:
247 typedef Vec3fa value_type;
248
249 /*! access to the ith element of the buffer */
250 __forceinline const Vec3fa operator [](size_t i) const
251 {
252 assert(i<num);
253 return Vec3fa(vfloat4::loadu((float*)(ptr_ofs + i*stride)));
254 }
255
256 /*! writes the i'th element */
257 __forceinline void store(size_t i, const Vec3fa& v)
258 {
259 assert(i<num);
260 vfloat4::storeu((float*)(ptr_ofs + i*stride), (vfloat4)v);
261 }
262 };
263}
264