1// ======================================================================== //
2// Copyright 2009-2019 Intel Corporation //
3// //
4// Licensed under the Apache License, Version 2.0 (the "License"); //
5// you may not use this file except in compliance with the License. //
6// You may obtain a copy of the License at //
7// //
8// http://www.apache.org/licenses/LICENSE-2.0 //
9// //
10// Unless required by applicable law or agreed to in writing, software //
11// distributed under the License is distributed on an "AS IS" BASIS, //
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
13// See the License for the specific language governing permissions and //
14// limitations under the License. //
15// ======================================================================== //
16
17#include "device.h"
18#include "autoencoder.h"
19
20namespace oidn {
21
22 thread_local Device::ErrorState Device::globalError;
23
24 Device::Device()
25 {
26 if (!mayiuse(sse41))
27 throw Exception(Error::UnsupportedHardware, "SSE4.1 support is required at minimum");
28 }
29
30 Device::~Device()
31 {
32 // -- GODOT start --
33 //observer.reset();
34 // -- GODOT end --
35 }
36
37 void Device::setError(Device* device, Error code, const std::string& message)
38 {
39 // Update the stored error only if the previous error was queried
40 if (device)
41 {
42 ErrorState& curError = device->error.get();
43
44 if (curError.code == Error::None)
45 {
46 curError.code = code;
47 curError.message = message;
48 }
49
50 // Print the error message in verbose mode
51 if (device->isVerbose())
52 std::cerr << "Error: " << message << std::endl;
53
54 // Call the error callback function
55 ErrorFunction errorFunc;
56 void* errorUserPtr;
57
58 {
59 std::lock_guard<std::mutex> lock(device->mutex);
60 errorFunc = device->errorFunc;
61 errorUserPtr = device->errorUserPtr;
62 }
63
64 if (errorFunc)
65 errorFunc(errorUserPtr, code, (code == Error::None) ? nullptr : message.c_str());
66 }
67 else
68 {
69 if (globalError.code == Error::None)
70 {
71 globalError.code = code;
72 globalError.message = message;
73 }
74 }
75 }
76
77 Error Device::getError(Device* device, const char** outMessage)
78 {
79 // Return and clear the stored error code, but keep the error message so pointers to it will
80 // remain valid until the next getError call
81 if (device)
82 {
83 ErrorState& curError = device->error.get();
84 const Error code = curError.code;
85 if (outMessage)
86 *outMessage = (code == Error::None) ? nullptr : curError.message.c_str();
87 curError.code = Error::None;
88 return code;
89 }
90 else
91 {
92 const Error code = globalError.code;
93 if (outMessage)
94 *outMessage = (code == Error::None) ? nullptr : globalError.message.c_str();
95 globalError.code = Error::None;
96 return code;
97 }
98 }
99
100 void Device::setErrorFunction(ErrorFunction func, void* userPtr)
101 {
102 errorFunc = func;
103 errorUserPtr = userPtr;
104 }
105
106 int Device::get1i(const std::string& name)
107 {
108 if (name == "numThreads")
109 return numThreads;
110 else if (name == "setAffinity")
111 return setAffinity;
112 else if (name == "verbose")
113 return verbose;
114 else if (name == "version")
115 return OIDN_VERSION;
116 else if (name == "versionMajor")
117 return OIDN_VERSION_MAJOR;
118 else if (name == "versionMinor")
119 return OIDN_VERSION_MINOR;
120 else if (name == "versionPatch")
121 return OIDN_VERSION_PATCH;
122 else
123 throw Exception(Error::InvalidArgument, "invalid parameter");
124 }
125
126 void Device::set1i(const std::string& name, int value)
127 {
128 if (name == "numThreads")
129 numThreads = value;
130 else if (name == "setAffinity")
131 setAffinity = value;
132 else if (name == "verbose")
133 {
134 verbose = value;
135 error.verbose = value;
136 }
137
138 dirty = true;
139 }
140
141 void Device::commit()
142 {
143 if (isCommitted())
144 throw Exception(Error::InvalidOperation, "device can be committed only once");
145
146 // -- GODOT start --
147 #if 0
148 // -- GODOT end --
149 // Get the optimal thread affinities
150 if (setAffinity)
151 {
152 affinity = std::make_shared<ThreadAffinity>(1, verbose); // one thread per core
153 if (affinity->getNumThreads() == 0)
154 affinity.reset();
155 }
156
157 // Create the task arena
158 const int maxNumThreads = affinity ? affinity->getNumThreads() : tbb::this_task_arena::max_concurrency();
159 numThreads = (numThreads > 0) ? min(numThreads, maxNumThreads) : maxNumThreads;
160 arena = std::make_shared<tbb::task_arena>(numThreads);
161
162 // Automatically set the thread affinities
163 if (affinity)
164 observer = std::make_shared<PinningObserver>(affinity, *arena);
165 // -- GODOT start --
166 #endif
167 numThreads = 1;
168 // -- GODOT end --
169 dirty = false;
170
171 if (isVerbose())
172 print();
173 }
174
175 void Device::checkCommitted()
176 {
177 if (dirty)
178 throw Exception(Error::InvalidOperation, "changes to the device are not committed");
179 }
180
181 Ref<Buffer> Device::newBuffer(size_t byteSize)
182 {
183 checkCommitted();
184 return makeRef<Buffer>(Ref<Device>(this), byteSize);
185 }
186
187 Ref<Buffer> Device::newBuffer(void* ptr, size_t byteSize)
188 {
189 checkCommitted();
190 return makeRef<Buffer>(Ref<Device>(this), ptr, byteSize);
191 }
192
193 Ref<Filter> Device::newFilter(const std::string& type)
194 {
195 checkCommitted();
196
197 if (isVerbose())
198 std::cout << "Filter: " << type << std::endl;
199
200 Ref<Filter> filter;
201
202// -- GODOT start --
203// Godot doesn't need Raytracing filters. Removing them saves space in the weights files.
204#if 0
205// -- GODOT end --
206 if (type == "RT")
207 filter = makeRef<RTFilter>(Ref<Device>(this));
208// -- GODOT start --
209// Godot doesn't need Raytracing filters. Removing them saves space in the weights files.
210#endif
211 if (type == "RTLightmap")
212// -- GODOT end --
213 filter = makeRef<RTLightmapFilter>(Ref<Device>(this));
214 else
215 throw Exception(Error::InvalidArgument, "unknown filter type");
216
217 return filter;
218 }
219
220 void Device::print()
221 {
222 std::cout << std::endl;
223
224 std::cout << "Intel(R) Open Image Denoise " << OIDN_VERSION_STRING << std::endl;
225 std::cout << " Compiler: " << getCompilerName() << std::endl;
226 std::cout << " Build : " << getBuildName() << std::endl;
227 std::cout << " Platform: " << getPlatformName() << std::endl;
228
229// -- GODOT start --
230// std::cout << " Tasking :";
231// std::cout << " TBB" << TBB_VERSION_MAJOR << "." << TBB_VERSION_MINOR;
232// std::cout << " TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << tbb::TBB_runtime_interface_version();
233// std::cout << std::endl;
234// -- GODOT end --
235 std::cout << std::endl;
236 }
237
238} // namespace oidn
239