1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/lite/delegates/gpu/gl/runtime.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <vector>
21
22 #include "absl/status/status.h"
23 #include "absl/strings/str_cat.h"
24 #include "tensorflow/lite/delegates/gpu/common/data_type.h"
25 #include "tensorflow/lite/delegates/gpu/common/gpu_info.h"
26 #include "tensorflow/lite/delegates/gpu/common/memory_management.h"
27 #include "tensorflow/lite/delegates/gpu/common/memory_management/types.h"
28 #include "tensorflow/lite/delegates/gpu/common/status.h"
29 #include "tensorflow/lite/delegates/gpu/common/types.h"
30 #include "tensorflow/lite/delegates/gpu/gl/gl_call.h"
31 #include "tensorflow/lite/delegates/gpu/gl/gl_errors.h"
32 #include "tensorflow/lite/delegates/gpu/gl/gl_program.h"
33 #include "tensorflow/lite/delegates/gpu/gl/gl_texture.h"
34 #include "tensorflow/lite/delegates/gpu/gl/object.h"
35 #include "tensorflow/lite/delegates/gpu/gl/portable_gl31.h"
36 #include "tensorflow/lite/delegates/gpu/gl/variable.h"
37
38 namespace tflite {
39 namespace gpu {
40 namespace gl {
41 namespace {
42
43 struct TextureF16Maker {
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF16Maker44 absl::Status operator()(const uint3& size) const {
45 return CreateReadOnlyImageTextureF16(size, data, gl_texture);
46 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF16Maker47 absl::Status operator()(const uint2& size) const {
48 return CreateReadOnlyImageTextureF16(size, data, gl_texture);
49 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF16Maker50 absl::Status operator()(const size_t& size) const {
51 return CreateReadOnlyImageTextureF16(uint2(static_cast<uint32_t>(size), 1U),
52 data, gl_texture);
53 }
54 absl::Span<const uint16_t> data;
55 GlTexture* gl_texture;
56 };
57
58 struct TextureF32Maker {
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF32Maker59 absl::Status operator()(const uint3& size) const {
60 return CreateReadOnlyImageTexture(size, data, gl_texture);
61 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF32Maker62 absl::Status operator()(const uint2& size) const {
63 return CreateReadOnlyImageTexture(size, data, gl_texture);
64 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureF32Maker65 absl::Status operator()(const size_t& size) const {
66 return CreateReadOnlyImageTexture(uint2(static_cast<uint32_t>(size), 1U),
67 data, gl_texture);
68 }
69 absl::Span<const float> data;
70 GlTexture* gl_texture;
71 };
72
MakeGlTexture(const Object & object,const ObjectData & data,GlTexture * gl_texture)73 absl::Status MakeGlTexture(const Object& object, const ObjectData& data,
74 GlTexture* gl_texture) {
75 if (object.access == AccessType::READ_WRITE ||
76 object.access == AccessType::WRITE) {
77 return absl::InvalidArgumentError("Read-write textures are not supported");
78 }
79 if (object.data_type != DataType::FLOAT16 &&
80 object.data_type != DataType::FLOAT32) {
81 return absl::InvalidArgumentError(
82 "Textures support float16 or float32 only.");
83 }
84 switch (object.data_type) {
85 case DataType::FLOAT16: {
86 if (data.size() % 2 != 0) {
87 return absl::InvalidArgumentError("Texture size is not aligned");
88 }
89 return absl::visit(
90 TextureF16Maker{
91 .data = absl::MakeConstSpan(
92 reinterpret_cast<const uint16_t*>(data.data()),
93 data.size() / 2),
94 .gl_texture = gl_texture,
95 },
96 object.size);
97 }
98 case DataType::FLOAT32: {
99 if (data.size() % sizeof(float) != 0) {
100 return absl::InvalidArgumentError("Texture size is not aligned");
101 }
102 return absl::visit(
103 TextureF32Maker{
104 .data = absl::MakeConstSpan(
105 reinterpret_cast<const float*>(data.data()),
106 data.size() / sizeof(float)),
107 .gl_texture = gl_texture,
108 },
109 object.size);
110 }
111 default:
112 return absl::InvalidArgumentError("Unsupported textures data type.");
113 }
114 }
115
116 struct TextureRefMaker {
operator ()tflite::gpu::gl::__anonb40242c40111::TextureRefMaker117 absl::Status operator()(const uint3& size) const {
118 return CreateReadWriteRgbaImageTexture(type, size, gl_texture);
119 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureRefMaker120 absl::Status operator()(const uint2& size) const {
121 return CreateReadWriteRgbaImageTexture(type, size, gl_texture);
122 }
operator ()tflite::gpu::gl::__anonb40242c40111::TextureRefMaker123 absl::Status operator()(const size_t& size) const {
124 return CreateReadWriteRgbaImageTexture(
125 type, uint2(static_cast<uint32_t>(size), 1U), gl_texture);
126 }
127 DataType type;
128 GlTexture* gl_texture;
129 };
130
131 // Makes read-write gl texture
MakeGlTextureRef(const Object & object,GlTexture * gl_texture)132 absl::Status MakeGlTextureRef(const Object& object, GlTexture* gl_texture) {
133 return absl::visit(TextureRefMaker{object.data_type, gl_texture},
134 object.size);
135 }
136
MakeGlBuffer(const Object & object,const ObjectData & data,GlBuffer * gl_buffer)137 absl::Status MakeGlBuffer(const Object& object, const ObjectData& data,
138 GlBuffer* gl_buffer) {
139 if (data.size() % SizeOf(object.data_type) != 0) {
140 return absl::InvalidArgumentError("Buffer size is not aligned");
141 }
142 return CreateReadOnlyShaderStorageBuffer(absl::MakeConstSpan(data),
143 gl_buffer);
144 }
145
MakeBindingFunc(const Object & object,uint32_t id,const ObjectManager * objects,std::function<absl::Status ()> * binding_func)146 absl::Status MakeBindingFunc(const Object& object, uint32_t id,
147 const ObjectManager* objects,
148 std::function<absl::Status()>* binding_func) {
149 const uint32_t binding = object.binding;
150 switch (object.object_type) {
151 case ObjectType::BUFFER: {
152 auto ptr = objects->FindBuffer(id);
153 if (!ptr) {
154 return absl::NotFoundError(
155 absl::StrCat("Buffer ", id, " is not found"));
156 }
157 size_t size_in_bytes = ByteSizeOf(object);
158 // TODO(akulik): make comparison != instead of <
159 if (ptr->bytes_size() < size_in_bytes) {
160 return absl::FailedPreconditionError(
161 absl::StrCat("Buffer ", id, " size in bytes ", ptr->bytes_size(),
162 " < requested size_in_bytes ", size_in_bytes));
163 }
164 *binding_func = [=]() { return ptr->BindToIndex(binding); };
165 break;
166 }
167 case ObjectType::TEXTURE: {
168 auto ptr = objects->FindTexture(id);
169 if (!ptr) {
170 return absl::NotFoundError(
171 absl::StrCat("Texture ", id, " is not found"));
172 }
173 *binding_func = [=]() { return ptr->BindAsReadWriteImage(binding); };
174 break;
175 }
176 case ObjectType::UNKNOWN:
177 return absl::InvalidArgumentError("Unknown object type");
178 }
179 return absl::OkStatus();
180 }
181
182 // TODO(b/147771327): think about merging this function with MakeBindingFunc()
MakeLateBindingFunc(const Object & object,uint32_t id,const ObjectManager * objects,std::function<absl::Status ()> * binding_func)183 absl::Status MakeLateBindingFunc(const Object& object, uint32_t id,
184 const ObjectManager* objects,
185 std::function<absl::Status()>* binding_func) {
186 const uint32_t binding = object.binding;
187 switch (object.object_type) {
188 case ObjectType::BUFFER: {
189 auto ptr = objects->FindBuffer(id);
190 if (!ptr) {
191 return absl::NotFoundError(
192 absl::StrCat("Buffer ", id, " is not found"));
193 }
194 *binding_func = [=]() {
195 auto ptr = objects->FindBuffer(id);
196 if (!ptr) {
197 return absl::NotFoundError(
198 absl::StrCat("Buffer ", id, " is not found"));
199 }
200 if (!ptr->is_valid()) {
201 return absl::InvalidArgumentError("Buffer is not initialized.");
202 }
203 size_t size_in_bytes = ByteSizeOf(object);
204 if (ptr->bytes_size() < size_in_bytes) {
205 return absl::FailedPreconditionError(
206 absl::StrCat("Buffer ", id, " size in bytes ", ptr->bytes_size(),
207 " < requested size_in_bytes ", size_in_bytes));
208 }
209 return ptr->BindToIndex(binding);
210 };
211 break;
212 }
213 case ObjectType::TEXTURE: {
214 auto ptr = objects->FindTexture(id);
215 if (!ptr) {
216 return absl::NotFoundError(
217 absl::StrCat("Texture ", id, " is not found"));
218 }
219 *binding_func = [=]() {
220 auto ptr = objects->FindTexture(id);
221 if (!ptr) {
222 return absl::NotFoundError(
223 absl::StrCat("Texture ", id, " is not found"));
224 }
225 if (!ptr->is_valid()) {
226 return absl::InvalidArgumentError("Texture is not initialized.");
227 }
228 return ptr->BindAsReadWriteImage(binding);
229 };
230 break;
231 }
232 case ObjectType::UNKNOWN:
233 return absl::InvalidArgumentError("Unknown object type");
234 }
235 return absl::OkStatus();
236 }
237
238 } // namespace
239
Runtime(const RuntimeOptions & options,const GpuInfo & gpu_info,CommandQueue * command_queue,const ObjectManager * external_objects)240 Runtime::Runtime(const RuntimeOptions& options, const GpuInfo& gpu_info,
241 CommandQueue* command_queue,
242 const ObjectManager* external_objects)
243 : options_(options),
244 gpu_info_(gpu_info),
245 external_objects_(external_objects),
246 command_queue_(command_queue) {
247 programs_.reserve(256);
248 if (options_.bundle_readonly_objects) {
249 shared_readonly_buffer_ = absl::make_unique<SharedBufferData>();
250 }
251 }
252
AddProgram(const GlShader & shader,const std::vector<Variable> & parameters,const std::vector<Object> & objects,const uint3 & num_workgroups)253 absl::Status Runtime::AddProgram(const GlShader& shader,
254 const std::vector<Variable>& parameters,
255 const std::vector<Object>& objects,
256 const uint3& num_workgroups) {
257 GlProgram program;
258 RETURN_IF_ERROR(GlProgram::CreateWithShader(shader, &program));
259
260 for (auto& parameter : parameters) {
261 RETURN_IF_ERROR(program.SetParameter(parameter));
262 }
263
264 programs_.emplace_back(
265 CompiledProgramDescriptor{std::move(program), num_workgroups, {}});
266
267 // Create const buffers, resolve external references and collect internal
268 // buffer references.
269 for (auto& object : objects) {
270 auto& program = programs_.back();
271 BindFunc binding_func;
272 if (IsRef(object)) {
273 // Reference object could be provided externally as a model input/output
274 // but also for debugging purposes. Otherwise all references are collected
275 // and allocated later.
276 absl::Status status = MakeLateBindingFunc(
277 object, GetRef(object), external_objects_, &binding_func);
278 if (!status.ok()) {
279 if (absl::IsNotFound(status)) {
280 program.refs.push_back(object);
281 continue; // don't add to binding.
282 }
283 return status;
284 }
285 } else {
286 // Allocate const object.
287 uint32_t id;
288 RETURN_IF_ERROR(AllocateConstObject(object, &id));
289 RETURN_IF_ERROR(
290 MakeBindingFunc(object, id, &const_objects_, &binding_func));
291 }
292 program.bindings.push_back(std::move(binding_func));
293 }
294
295 // All parameters once set stay with program, therefore, we only need to keep
296 // program and bindings for execution.
297 return absl::OkStatus();
298 }
299
AllocateInternalObject(const Object & object)300 absl::Status Runtime::AllocateInternalObject(const Object& object) {
301 const ObjectRef ref = GetRef(object);
302 switch (object.object_type) {
303 case ObjectType::BUFFER: {
304 GlBuffer gl_buffer;
305 RETURN_IF_ERROR(CreateReadWriteShaderStorageBuffer<uint8_t>(
306 ByteSizeOf(object), &gl_buffer));
307 RETURN_IF_ERROR(
308 internal_objects_.RegisterBuffer(ref, std::move(gl_buffer)));
309 break;
310 }
311 case ObjectType::TEXTURE: {
312 GlTexture gl_texture;
313 RETURN_IF_ERROR(MakeGlTextureRef(object, &gl_texture));
314 RETURN_IF_ERROR(
315 internal_objects_.RegisterTexture(ref, std::move(gl_texture)));
316 break;
317 }
318 default:
319 return absl::InternalError("Unexpected internal object type");
320 }
321 return absl::OkStatus();
322 }
323
AllocateConstObject(const Object & object,uint32_t * id)324 absl::Status Runtime::AllocateConstObject(const Object& object, uint32_t* id) {
325 const ObjectData* data = GetData(object);
326 if (data == nullptr) {
327 return absl::InternalError(
328 "Unable to allocate reference as a const object");
329 }
330 *id = next_const_id_++;
331 switch (object.object_type) {
332 case ObjectType::BUFFER: {
333 GlBuffer gl_buffer;
334 if (!shared_readonly_buffer_ ||
335 !shared_readonly_buffer_->Add(*data, &gl_buffer)) {
336 RETURN_IF_ERROR(MakeGlBuffer(object, *data, &gl_buffer));
337 }
338 RETURN_IF_ERROR(const_objects_.RegisterBuffer(*id, std::move(gl_buffer)));
339 break;
340 }
341 case ObjectType::TEXTURE: {
342 GlTexture gl_texture;
343 RETURN_IF_ERROR(MakeGlTexture(object, *data, &gl_texture));
344 RETURN_IF_ERROR(
345 const_objects_.RegisterTexture(*id, std::move(gl_texture)));
346 break;
347 }
348 case ObjectType::UNKNOWN:
349 return absl::InternalError("Unknown object type");
350 }
351 return absl::OkStatus();
352 }
353
PrepareForExecution()354 absl::Status Runtime::PrepareForExecution() {
355 if (shared_readonly_buffer_ && !shared_readonly_buffer_->empty()) {
356 GlBuffer shared_buffer;
357 RETURN_IF_ERROR(
358 shared_readonly_buffer_->CreateSharedGlBuffer(&shared_buffer));
359 shared_readonly_buffer_.reset(nullptr);
360 RETURN_IF_ERROR(const_objects_.RegisterBuffer(next_const_id_++,
361 std::move(shared_buffer)));
362 }
363
364 if (options_.reuse_internal_objects) {
365 // Analyze internal objects and make a pool of shared objects to be re-used
366 // by them. These shared objects need to be allocated upfront.
367 std::vector<Object> shared_objects;
368 RETURN_IF_ERROR(AssignInternalObjects(&shared_objects));
369 for (const Object& object : shared_objects) {
370 RETURN_IF_ERROR(AllocateInternalObject(object));
371 }
372 }
373
374 // Allocate all internal objects and create bindings for them.
375 for (auto& program : programs_) {
376 for (auto& object : program.refs) {
377 // Check whether it is created already.
378 BindFunc binding;
379 ObjectRef ref = GetRef(object);
380 absl::Status status =
381 MakeBindingFunc(object, ref, &internal_objects_, &binding);
382 if (!status.ok()) {
383 if (absl::IsNotFound(status)) {
384 RETURN_IF_ERROR(AllocateInternalObject(object));
385 RETURN_IF_ERROR(
386 MakeBindingFunc(object, ref, &internal_objects_, &binding));
387 } else {
388 return status;
389 }
390 }
391 program.bindings.push_back(std::move(binding));
392 }
393 program.refs.clear();
394 }
395 return absl::OkStatus();
396 }
397
398 namespace {
399
400 const size_t kNotAssigned = std::numeric_limits<size_t>::max();
401
402 struct CombinedUsageRecords {
403 std::vector<TensorUsageRecord<size_t>> buffers;
404 std::vector<TensorUsageRecord<size_t>> textures_1d;
405 std::vector<TensorUsageRecord<uint2>> textures_2d;
406 std::vector<TensorUsageRecord<uint3>> textures_3d;
407 std::vector<size_t> usage_refs;
408 };
409
410 template <typename TensorSizeT>
UpdateUsageRecord(TensorUsageRecord<TensorSizeT> * usage_rec,size_t task_id)411 void UpdateUsageRecord(TensorUsageRecord<TensorSizeT>* usage_rec,
412 size_t task_id) {
413 usage_rec->first_task = std::min(usage_rec->first_task, task_id);
414 usage_rec->last_task = std::max(usage_rec->last_task, task_id);
415 }
416
417 struct AddUsageRecordForTextureFunc {
operator ()tflite::gpu::gl::__anonb40242c40611::AddUsageRecordForTextureFunc418 void operator()(const uint3& size) const {
419 auto& usage_ref = usage_records->usage_refs[object_ref];
420 if (usage_ref == kNotAssigned) {
421 usage_ref = usage_records->textures_3d.size();
422 usage_records->textures_3d.emplace_back(/*tensor_size=*/size,
423 /*first_task=*/program_id,
424 /*last_task=*/program_id);
425 } else {
426 UpdateUsageRecord(&usage_records->textures_3d[usage_ref], program_id);
427 }
428 }
429
operator ()tflite::gpu::gl::__anonb40242c40611::AddUsageRecordForTextureFunc430 void operator()(const uint2& size) const {
431 auto& usage_ref = usage_records->usage_refs[object_ref];
432 if (usage_ref == kNotAssigned) {
433 usage_ref = usage_records->textures_2d.size();
434 usage_records->textures_2d.emplace_back(/*tensor_size=*/size,
435 /*first_task=*/program_id,
436 /*last_task=*/program_id);
437 } else {
438 UpdateUsageRecord(&usage_records->textures_2d[usage_ref], program_id);
439 }
440 }
441
operator ()tflite::gpu::gl::__anonb40242c40611::AddUsageRecordForTextureFunc442 void operator()(size_t size) const {
443 auto& usage_ref = usage_records->usage_refs[object_ref];
444 if (usage_ref == kNotAssigned) {
445 usage_ref = usage_records->textures_1d.size();
446 usage_records->textures_1d.emplace_back(/*tensor_size=*/size,
447 /*first_task=*/program_id,
448 /*last_task=*/program_id);
449 } else {
450 UpdateUsageRecord(&usage_records->textures_1d[usage_ref], program_id);
451 }
452 }
453
454 CombinedUsageRecords* usage_records;
455 const ObjectRef& object_ref;
456 const size_t program_id;
457 };
458
459 // We assume that AddUsageRecord for different objects is called in order of
460 // program_id.
AddUsageRecord(CombinedUsageRecords * usage_records,const Object & object,const size_t program_id)461 absl::Status AddUsageRecord(CombinedUsageRecords* usage_records,
462 const Object& object, const size_t program_id) {
463 auto ref = GetRef(object);
464 if (ref >= usage_records->usage_refs.size()) {
465 usage_records->usage_refs.resize(ref + 1, kNotAssigned);
466 }
467 auto& usage_ref = usage_records->usage_refs[ref];
468 if (object.object_type == ObjectType::BUFFER) {
469 if (usage_ref == kNotAssigned) {
470 usage_ref = usage_records->buffers.size();
471 usage_records->buffers.emplace_back(
472 /*tensor_size=*/NumElements(object.size),
473 /*first_task=*/program_id,
474 /*last_task=*/program_id);
475 } else {
476 UpdateUsageRecord(&usage_records->buffers[usage_ref], program_id);
477 }
478 return absl::OkStatus();
479 }
480 if (object.object_type == ObjectType::TEXTURE) {
481 absl::visit(AddUsageRecordForTextureFunc{usage_records, ref, program_id},
482 object.size);
483 return absl::OkStatus();
484 }
485 return absl::InternalError("Unexpected object type");
486 }
487
ApplyBuffersAssignment(const ObjectsAssignment<size_t> & assignment,const std::vector<size_t> & global_ref_to_usage_rec,const std::vector<Object * > & global_ref_to_object_ptr,std::vector<ObjectRef> * global_ref_to_shared_ref,std::vector<Object> * shared_objects)488 absl::Status ApplyBuffersAssignment(
489 const ObjectsAssignment<size_t>& assignment,
490 const std::vector<size_t>& global_ref_to_usage_rec,
491 const std::vector<Object*>& global_ref_to_object_ptr,
492 std::vector<ObjectRef>* global_ref_to_shared_ref,
493 std::vector<Object>* shared_objects) {
494 std::vector<ObjectRef> assigned_id_to_shared_ref(
495 assignment.object_sizes.size(), kInvalidObjectRef);
496 for (size_t global_ref = 0; global_ref < global_ref_to_usage_rec.size();
497 ++global_ref) {
498 const auto& usage_rec_id = global_ref_to_usage_rec[global_ref];
499 Object* object = global_ref_to_object_ptr[global_ref];
500 if (usage_rec_id == kNotAssigned || object == nullptr ||
501 object->object_type != ObjectType::BUFFER) {
502 // Skip objects with other data type and non-buffers.
503 continue;
504 }
505
506 // id of shared object, returned by memory allocation algorithm.
507 size_t assigned_id = assignment.object_ids[usage_rec_id];
508
509 // id of corresponding shared object in vector share_objects.
510 ObjectRef shared_ref = assigned_id_to_shared_ref[assigned_id];
511
512 if (shared_ref == kInvalidObjectRef) {
513 // We need to create new shared object for current buffer.
514 shared_ref = shared_objects->size();
515 Object shared_object = *object;
516 shared_object.access = AccessType::READ_WRITE;
517 shared_object.object = shared_ref;
518 shared_object.size = assignment.object_sizes[assigned_id];
519 shared_objects->push_back(std::move(shared_object));
520 assigned_id_to_shared_ref[assigned_id] = shared_ref;
521 }
522 (*global_ref_to_shared_ref)[global_ref] = shared_ref;
523 }
524 return absl::OkStatus();
525 }
526
527 template <typename ObjectSizeT>
ApplyTexturesAssignment(const ObjectsAssignment<ObjectSizeT> & assignment,const std::vector<size_t> & global_ref_to_usage_rec,const std::vector<Object * > & global_ref_to_object_ptr,std::vector<ObjectRef> * global_ref_to_shared_ref,std::vector<Object> * shared_objects)528 absl::Status ApplyTexturesAssignment(
529 const ObjectsAssignment<ObjectSizeT>& assignment,
530 const std::vector<size_t>& global_ref_to_usage_rec,
531 const std::vector<Object*>& global_ref_to_object_ptr,
532 std::vector<ObjectRef>* global_ref_to_shared_ref,
533 std::vector<Object>* shared_objects) {
534 std::vector<ObjectRef> assigned_id_to_shared_ref(
535 assignment.object_sizes.size(), kInvalidObjectRef);
536 for (size_t global_ref = 0; global_ref < global_ref_to_usage_rec.size();
537 ++global_ref) {
538 const auto& usage_rec_id = global_ref_to_usage_rec[global_ref];
539 Object* object = global_ref_to_object_ptr[global_ref];
540 if (usage_rec_id == kNotAssigned || object == nullptr ||
541 object->object_type != ObjectType::TEXTURE ||
542 !absl::holds_alternative<ObjectSizeT>(object->size)) {
543 // Skip objects with other data type, non-textures and textures with wrong
544 // number of dimensions.
545 continue;
546 }
547
548 // id of shared object, returned by memory allocation algorithm.
549 size_t assigned_id = assignment.object_ids[usage_rec_id];
550
551 // id of corresponding shared object in vector share_objects.
552 ObjectRef shared_ref = assigned_id_to_shared_ref[assigned_id];
553
554 if (shared_ref == kInvalidObjectRef) {
555 // We need to create new shared object for current texture.
556 shared_ref = shared_objects->size();
557 Object shared_object = *object;
558 shared_object.access = AccessType::READ_WRITE;
559 shared_object.object = shared_ref;
560 shared_object.size = assignment.object_sizes[assigned_id];
561 shared_objects->push_back(std::move(shared_object));
562 assigned_id_to_shared_ref[assigned_id] = shared_ref;
563 }
564 (*global_ref_to_shared_ref)[global_ref] = shared_ref;
565 }
566 return absl::OkStatus();
567 }
568
569 } // namespace
570
571 // Assign shared objects to internal objects, using memory allocation
572 // algorithms. Usage records for the algorithms are calculated separately for
573 // each data type and object type.
AssignInternalObjects(std::vector<Object> * shared_objects)574 absl::Status Runtime::AssignInternalObjects(
575 std::vector<Object>* shared_objects) {
576 // Build tensor usage records, clusterized by object type and data type.
577 std::map<DataType, CombinedUsageRecords> usage_records_by_data_type;
578 std::vector<Object*> global_ref_to_object_ptr;
579 for (size_t i = 0; i < programs_.size(); ++i) {
580 for (auto& object : programs_[i].refs) {
581 auto ref = GetRef(object);
582 if (ref >= global_ref_to_object_ptr.size()) {
583 global_ref_to_object_ptr.resize(ref + 1, nullptr);
584 }
585 if (global_ref_to_object_ptr[ref] == nullptr) {
586 global_ref_to_object_ptr[ref] = &object;
587 }
588 RETURN_IF_ERROR(AddUsageRecord(
589 &usage_records_by_data_type[object.data_type], object, i));
590 }
591 }
592
593 std::vector<ObjectRef> global_ref_to_shared_ref(
594 global_ref_to_object_ptr.size(), kInvalidObjectRef);
595
596 // Calculate and apply shared objects assignment for each data type.
597 for (const auto& it : usage_records_by_data_type) {
598 const CombinedUsageRecords& usage_records = it.second;
599 if (!usage_records.buffers.empty()) {
600 ObjectsAssignment<size_t> buffer_assignment;
601 RETURN_IF_ERROR(AssignObjectsToTensors(usage_records.buffers,
602 MemoryStrategy::GREEDY_BEST,
603 &buffer_assignment));
604 RETURN_IF_ERROR(ApplyBuffersAssignment(
605 buffer_assignment, usage_records.usage_refs, global_ref_to_object_ptr,
606 &global_ref_to_shared_ref, shared_objects));
607 }
608 if (!usage_records.textures_1d.empty()) {
609 ObjectsAssignment<size_t> texture_1d_assignment;
610 RETURN_IF_ERROR(AssignObjectsToTensors(usage_records.textures_1d,
611 MemoryStrategy::GREEDY_BEST,
612 &texture_1d_assignment));
613 RETURN_IF_ERROR(ApplyTexturesAssignment(
614 texture_1d_assignment, usage_records.usage_refs,
615 global_ref_to_object_ptr, &global_ref_to_shared_ref, shared_objects));
616 }
617 if (!usage_records.textures_2d.empty()) {
618 ObjectsAssignment<uint2> texture_2d_assignment;
619 RETURN_IF_ERROR(AssignObjectsToTensors(usage_records.textures_2d,
620 MemoryStrategy::GREEDY_IN_ORDER,
621 &texture_2d_assignment));
622 RETURN_IF_ERROR(ApplyTexturesAssignment(
623 texture_2d_assignment, usage_records.usage_refs,
624 global_ref_to_object_ptr, &global_ref_to_shared_ref, shared_objects));
625 }
626 if (!usage_records.textures_3d.empty()) {
627 ObjectsAssignment<uint3> texture_3d_assignment;
628 RETURN_IF_ERROR(AssignObjectsToTensors(usage_records.textures_3d,
629 MemoryStrategy::GREEDY_IN_ORDER,
630 &texture_3d_assignment));
631 RETURN_IF_ERROR(ApplyTexturesAssignment(
632 texture_3d_assignment, usage_records.usage_refs,
633 global_ref_to_object_ptr, &global_ref_to_shared_ref, shared_objects));
634 }
635 }
636
637 for (size_t i = 0; i < programs_.size(); ++i) {
638 for (auto& object : programs_[i].refs) {
639 object.object = global_ref_to_shared_ref[GetRef(object)];
640 }
641 }
642 return absl::OkStatus();
643 }
644
Execute()645 absl::Status Runtime::Execute() {
646 for (const auto& descriptor : programs_) {
647 for (auto& b : descriptor.bindings) {
648 RETURN_IF_ERROR(b());
649 }
650 RETURN_IF_ERROR(command_queue_->Dispatch(descriptor.program,
651 descriptor.num_workgroups));
652 }
653 return absl::OkStatus();
654 }
655
656 } // namespace gl
657 } // namespace gpu
658 } // namespace tflite
659