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 | |
20 | namespace 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 | |