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