Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
renderer.cc
Go to the documentation of this file.
1 
18 #include <algorithm>
19 #include <array>
20 #include <bitset>
21 #include <limits>
22 #include <memory>
23 #include <vector>
24 
25 #include "base/integral_types.h"
28 #include "ion/base/enumhelper.h"
29 #include "ion/base/invalid.h"
30 #include "ion/base/lockguards.h"
31 #include "ion/base/logging.h"
32 #include "ion/base/readwritelock.h"
33 #include "ion/base/serialize.h"
38 #include "ion/gfx/attribute.h"
39 #include "ion/gfx/attributearray.h"
40 #include "ion/gfx/bufferobject.h"
41 #include "ion/gfx/cubemaptexture.h"
43 #include "ion/gfx/image.h"
44 #include "ion/gfx/renderer.h"
45 #include "ion/gfx/resourcebase.h"
47 #include "ion/gfx/shape.h"
48 #include "ion/gfx/texture.h"
49 #include "ion/gfx/texturemanager.h"
51 #include "ion/math/matrix.h"
52 #include "ion/math/matrixutils.h"
53 #include "ion/math/range.h"
54 #include "ion/math/rangeutils.h"
55 #include "ion/math/utils.h"
56 #include "ion/math/vector.h"
57 #include "ion/port/atomic.h"
58 #include "ion/port/macros.h"
59 #include "ion/port/mutex.h"
60 #include "ion/portgfx/glheaders.h"
61 #include "ion/portgfx/visual.h"
62 
63 namespace ion {
64 namespace gfx {
65 
66 using base::DataContainer;
68 using math::Point3ui;
69 using math::Range1i;
70 using math::Range1ui;
71 
72 namespace {
73 
74 static const GLuint kInvalidGluint = static_cast<GLuint>(-1);
75 
77 
82 
83 
85 static base::ReadWriteLock* GetResourceBinderLock() {
86  ION_DECLARE_SAFE_STATIC_POINTER(base::ReadWriteLock, lock);
87  return lock;
88 }
89 
93 static void GetAttributeSlotCountAndStride(BufferObject::ComponentType type,
94  GLuint* stride, GLuint* slots) {
95  *stride = 0U;
96  *slots = 1U;
97  switch (type) {
99  *stride = static_cast<GLuint>(2U * sizeof(float));
100  *slots = 2U;
101  break;
103  *stride = static_cast<GLuint>(3U * sizeof(float));
104  *slots = 3U;
105  break;
107  *stride = static_cast<GLuint>(4U * sizeof(float));
108  *slots = 4U;
109  break;
110  default:
111  break;
112  }
113 }
114 
116 static GLuint GetAttributeSlotCountByGlType(GLenum type) {
117  GLuint slots = 1U;
118  switch (type) {
119  case GL_FLOAT_MAT2:
120  slots = 2U;
121  break;
122  case GL_FLOAT_MAT3:
123  slots = 3U;
124  break;
125  case GL_FLOAT_MAT4:
126  slots = 4U;
127  break;
128  default:
129  break;
130  }
131  return slots;
132 }
133 
135 static const char* GetShaderTypeString(GLenum shader_type) {
136  const char* type = "<UNKNOWN>";
137  if (shader_type == GL_VERTEX_SHADER)
138  type = "vertex";
139  else if (shader_type == GL_FRAGMENT_SHADER)
140  type = "fragment";
141  return type;
142 }
143 
145 static void SetObjectLabel(GraphicsManager* gm, GLenum type, GLuint id,
146  const std::string& label) {
147 #if !ION_PRODUCTION
148  if (gm->IsFunctionGroupAvailable(GraphicsManager::kDebugLabel)) {
149  gm->LabelObject(type, id, static_cast<GLsizei>(label.length()),
150  label.c_str());
151  }
152 #endif
153 }
154 
155 static bool ValidateUniformType(const char* name,
156  const Uniform::ValueType spec_type,
157  GLenum type) {
158  bool types_equal = false;
159  switch (spec_type) {
160  case kIntUniform:
161  types_equal = type == GL_INT;
162  break;
163  case kFloatUniform:
164  types_equal = type == GL_FLOAT;
165  break;
166  case kUnsignedIntUniform:
167  types_equal = type == GL_UNSIGNED_INT;
168  break;
170  types_equal = type == GL_INT_SAMPLER_CUBE ||
171  type == GL_INT_SAMPLER_CUBE_MAP_ARRAY ||
172  type == GL_SAMPLER_CUBE ||
173  type == GL_SAMPLER_CUBE_MAP_ARRAY ||
174  type == GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW ||
175  type == GL_SAMPLER_CUBE_SHADOW ||
176  type == GL_UNSIGNED_INT_SAMPLER_CUBE ||
177  type == GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY;
178  break;
179  case kTextureUniform:
180  types_equal =
181  type == GL_INT_SAMPLER_1D || type == GL_INT_SAMPLER_1D_ARRAY ||
182  type == GL_INT_SAMPLER_2D || type == GL_INT_SAMPLER_2D_ARRAY ||
183  type == GL_INT_SAMPLER_3D || type == GL_SAMPLER_1D ||
184  type == GL_SAMPLER_1D_ARRAY || type == GL_SAMPLER_1D_ARRAY_SHADOW ||
185  type == GL_SAMPLER_1D_SHADOW || type == GL_SAMPLER_2D ||
186  type == GL_SAMPLER_2D_ARRAY || type == GL_SAMPLER_2D_ARRAY_SHADOW ||
187  type == GL_SAMPLER_2D_MULTISAMPLE ||
188  type == GL_SAMPLER_2D_MULTISAMPLE_ARRAY ||
189  type == GL_SAMPLER_2D_SHADOW || type == GL_SAMPLER_3D ||
190  type == GL_SAMPLER_EXTERNAL_OES ||
191  type == GL_UNSIGNED_INT_SAMPLER_1D ||
192  type == GL_UNSIGNED_INT_SAMPLER_1D_ARRAY ||
193  type == GL_UNSIGNED_INT_SAMPLER_2D ||
194  type == GL_UNSIGNED_INT_SAMPLER_2D_ARRAY ||
195  type == GL_UNSIGNED_INT_SAMPLER_3D;
196  break;
198  types_equal = type == GL_FLOAT_VEC2;
199  break;
201  types_equal = type == GL_FLOAT_VEC3;
202  break;
204  types_equal = type == GL_FLOAT_VEC4;
205  break;
206  case kIntVector2Uniform:
207  types_equal = type == GL_INT_VEC2;
208  break;
209  case kIntVector3Uniform:
210  types_equal = type == GL_INT_VEC3;
211  break;
212  case kIntVector4Uniform:
213  types_equal = type == GL_INT_VEC4;
214  break;
215  case kMatrix2x2Uniform:
216  types_equal = type == GL_FLOAT_MAT2;
217  break;
218  case kMatrix3x3Uniform:
219  types_equal = type == GL_FLOAT_MAT3;
220  break;
221  case kMatrix4x4Uniform:
222  types_equal = type == GL_FLOAT_MAT4;
223  break;
225  types_equal = type == GL_UNSIGNED_INT_VEC2;
226  break;
228  types_equal = type == GL_UNSIGNED_INT_VEC3;
229  break;
231  types_equal = type == GL_UNSIGNED_INT_VEC4;
232  break;
233 #if !defined(ION_COVERAGE) // COV_NF_START
234  default:
236  break;
237 #endif // COV_NF_END
238  }
239 
240  return types_equal;
241 }
242 
245 static GLuint CompileShader(const std::string& id_string, GLenum shader_type,
246  const std::string& source, std::string* info_log,
247  GraphicsManager* gm) {
250  info_log->clear();
251  GLuint id = gm->CreateShader(shader_type);
252 
253  if (id) {
255  const char* source_string = source.c_str();
256  gm->ShaderSource(id, 1, &source_string, nullptr);
257  gm->CompileShader(id);
258 
260  GLint ok = GL_FALSE;
261  gm->GetShaderiv(id, GL_COMPILE_STATUS, &ok);
262  if (!ok) {
263  char log[2048];
264  log[0] = 0;
265  gm->GetShaderInfoLog(id, 2047, nullptr, log);
266  *info_log = log;
267  LOG(ERROR) << "***ION: Unable to compile "
268  << GetShaderTypeString(shader_type) << " shader for '"
269  << id_string << "': " << log;
270  gm->DeleteShader(id);
271  id = 0;
272  }
273  } else {
274  LOG(ERROR) << "***ION: Unable to create shader object";
275  }
276  return id;
277 }
278 
281 static GLuint RelinkShaderProgram(const std::string& id_string,
282  GLuint program_id, GLuint vertex_shader_id,
283  GLuint fragment_shader_id,
284  std::string* info_log, GraphicsManager* gm) {
287  info_log->clear();
289  gm->LinkProgram(program_id);
290 
292  GLint ok = GL_FALSE;
293  gm->GetProgramiv(program_id, GL_LINK_STATUS, &ok);
294  if (!ok) {
295  char log[2048];
296  log[0] = 0;
297  gm->GetProgramInfoLog(program_id, 2047, nullptr, log);
298  *info_log = log;
299  LOG(ERROR) << "***ION: Unable to link shader program for '" << id_string
300  << "': " << log;
301  gm->DeleteProgram(program_id);
302  program_id = 0;
303  }
304 
305  return program_id;
306 }
307 
310 static GLuint LinkShaderProgram(const std::string& id_string,
311  GLuint vertex_shader_id,
312  GLuint fragment_shader_id,
313  std::string* info_log, GraphicsManager* gm) {
314  GLuint program_id = gm->CreateProgram();
315  if (program_id) {
316  if (vertex_shader_id)
317  gm->AttachShader(program_id, vertex_shader_id);
318  if (fragment_shader_id)
319  gm->AttachShader(program_id, fragment_shader_id);
320 
321  program_id = RelinkShaderProgram(id_string, program_id, vertex_shader_id,
322  fragment_shader_id, info_log, gm);
323  } else {
324  LOG(ERROR) << "***ION: Unable to create shader program object";
325  }
326 
327  return program_id;
328 }
329 
332 const ImagePtr GetCubeMapTextureImageOrMipmap(const CubeMapTexture& tex,
335  const size_t mipmap_count = tex.GetImageCount(face);
336  for (size_t i = 0; i < mipmap_count; ++i) {
337  if (tex.HasImage(face, i))
338  return tex.GetImage(face, i);
339  }
340  return ImagePtr();
341 }
342 const ImagePtr GetTextureImageOrMipmap(const Texture& tex) {
343  ImagePtr image;
345  const size_t mipmap_count = tex.GetImageCount();
346  for (size_t i = 0; i < mipmap_count; ++i) {
347  if (tex.HasImage(i)) {
348  image = tex.GetImage(i);
349  break;
350  }
351  }
352  return image;
353 }
354 
356 class AttributeArrayEmulator : public AttributeArray {
357  public:
358  AttributeArrayEmulator() {}
359  ~AttributeArrayEmulator() override {}
360 };
361 
364 static Image::PixelFormat GetCompatiblePixelFormat(Image::PixelFormat pf,
365  GraphicsManager* gm) {
367  if (gm->GetGlVersion() >= 30 &&
368  gm->GetGlApiStandard() == GraphicsManager::kDesktop) {
369  if (pf.format == GL_LUMINANCE) {
370  pf.format = GL_RED;
371  pf.internal_format = GL_R8;
372  return pf;
373  } else if (pf.format == GL_LUMINANCE_ALPHA) {
374  pf.format = GL_RG;
375  pf.internal_format = GL_RG8;
376  return pf;
377  }
378  } else if (gm->GetGlVersion() < 30) {
380  if (pf.format == GL_RED) {
381  pf.format = pf.internal_format = GL_LUMINANCE;
382  return pf;
383  } else if (pf.format == GL_RG) {
384  pf.format = pf.internal_format = GL_LUMINANCE_ALPHA;
385  return pf;
386  }
387  }
388 
391  return pf;
392 }
393 
394 typedef void (GraphicsManager::*UniformMatrixSetter)(
395  GLint, GLsizei, GLboolean, const GLfloat*);
396 
397 template <int Dimension>
398 inline static void SendMatrixUniform(const Uniform& uniform,
399  GraphicsManager*gm,
400  GLint location,
401  UniformMatrixSetter setter) {
402  typedef math::Matrix<Dimension, float> Matrix;
403  if (uniform.IsArrayOf<Matrix>()) {
405  const GLint count = static_cast<GLint>(uniform.GetCount());
406  const base::AllocatorPtr& allocator =
409  Matrix* mats = static_cast<Matrix*>(allocator->AllocateMemory(
410  sizeof(Matrix) * count));
411  for (GLint i = 0; i < count; ++i)
412  mats[i] = math::Transpose(uniform.GetValueAt<Matrix>(i));
413  (gm->*setter)(location, count, GL_FALSE, reinterpret_cast<float*>(mats));
414  allocator->DeallocateMemory(mats);
415  } else {
416  (gm->*setter)(location, 1, GL_FALSE,
417  math::Transpose(uniform.GetValue<Matrix>()).Data());
418  }
419 }
420 
421 } // anonymous namespace
422 
423 
425 
430 
431 
432 template <typename T>
433 struct Renderer::HolderToResource {};
434 
436 template <>
437 struct Renderer::HolderToResource<AttributeArray> {
438  typedef Renderer::VertexArrayResource ResourceType;
439 };
440 template <>
441 struct Renderer::HolderToResource<AttributeArrayEmulator> {
442  typedef Renderer::VertexArrayEmulatorResource ResourceType;
443 };
444 template <>
445 struct Renderer::HolderToResource<BufferObject> {
446  typedef Renderer::BufferResource ResourceType;
447 };
448 template <>
449 struct Renderer::HolderToResource<CubeMapTexture> {
450  typedef Renderer::TextureResource ResourceType;
451 };
452 template <>
453 struct Renderer::HolderToResource<FramebufferObject> {
454  typedef Renderer::FramebufferResource ResourceType;
455 };
456 template <>
457 struct Renderer::HolderToResource<IndexBuffer> {
458  typedef Renderer::BufferResource ResourceType;
459 };
460 template <>
461 struct Renderer::HolderToResource<Sampler> {
462  typedef Renderer::SamplerResource ResourceType;
463 };
464 template <>
465 struct Renderer::HolderToResource<Shader> {
466  typedef Renderer::ShaderResource ResourceType;
467 };
468 template <>
469 struct Renderer::HolderToResource<ShaderProgram> {
470  typedef Renderer::ShaderProgramResource ResourceType;
471 };
472 template <>
473 struct Renderer::HolderToResource<ShaderInputRegistry> {
474  typedef Renderer::ShaderInputRegistryResource ResourceType;
475 };
476 template <>
477 struct Renderer::HolderToResource<TextureBase> {
478  typedef Renderer::TextureResource ResourceType;
479 };
480 template <>
481 struct Renderer::HolderToResource<Texture> {
482  typedef Renderer::TextureResource ResourceType;
483 };
484 
486 
493 
494 
495 class Renderer::ResourceManager : public gfx::ResourceManager {
496  public:
499  class Resource : public ResourceBase, public Allocatable {
500  public:
502  ResourceManager* GetResourceManager() const { return resource_manager_; }
503 
505  size_t GetGpuMemoryUsed() const override { return gpu_memory_used_.load(); }
506 
507  protected:
508  explicit Resource(ResourceManager* rm, const ResourceHolder* holder,
509  ResourceKey key)
510  : ResourceBase(holder, key),
511  index_(0),
512  resource_manager_(rm),
513  gpu_memory_used_(0U) {}
514 
517  virtual void Release(bool can_make_gl_calls) = 0;
518  virtual void Update(ResourceBinder* rb) = 0;
519  virtual void Unbind(ResourceBinder* rb) = 0;
520  virtual ResourceType GetType() const = 0;
521 
524  void SetUsedGpuMemory(size_t count) {
527  const ResourceType type = GetType();
528  const size_t old_used = gpu_memory_used_.load();
529  resource_manager_->IncreaseGpuMemoryUsage(type, count);
530  resource_manager_->DecreaseGpuMemoryUsage(type, old_used);
533  if (resource_manager_->GetAllocator().Get() &&
534  resource_manager_->GetAllocator()->GetTracker().Get() &&
535  resource_manager_->GetAllocator()
536  ->GetTracker()
537  ->GetGpuTracker()
538  .Get()) {
539  const base::AllocationSizeTrackerPtr& global_gpu_tracker =
540  resource_manager_->GetAllocator()->GetTracker()->GetGpuTracker();
541  UpdateAllocationSizeTracker(global_gpu_tracker, count, old_used);
542  }
545  if (GetAllocator()->GetTracker().Get() &&
546  GetAllocator()->GetTracker()->GetGpuTracker().Get()) {
547  const base::AllocationSizeTrackerPtr& gpu_tracker =
549  UpdateAllocationSizeTracker(gpu_tracker, count, old_used);
550  }
551  gpu_memory_used_ = count;
552  }
553 
557  template <typename HolderType>
558  typename HolderToResource<HolderType>::ResourceType* GetResource(
559  const HolderType* holder, ResourceBinder* binder, GLuint gl_id = 0) {
560  DCHECK(resource_manager_);
561  return resource_manager_->GetResource(holder, binder, gl_id);
562  }
563 
564  void UnbindAll() {
566  base::ReadLock read_lock(GetResourceBinderLock());
567  base::ReadGuard read_guard(&read_lock);
568  ResourceBinderMap& binders = GetResourceBinderMap();
569  for (ResourceBinderMap::iterator it = binders.begin();
570  it != binders.end();
571  ++it)
572  Unbind(it->second.get());
573  }
574 
575  private:
576  void SetIndex(size_t index) { index_ = index; }
577  size_t GetIndex() const { return index_; }
578 
581  void UpdateAllocationSizeTracker(
582  const base::AllocationSizeTrackerPtr& tracker, size_t count,
583  size_t old_used) {
584  if (count) tracker->TrackAllocationSize(count);
585  if (old_used) tracker->TrackDeallocationSize(old_used);
586  }
587 
589  size_t index_;
590 
593  ResourceManager* resource_manager_;
594 
596  std::atomic<size_t> gpu_memory_used_;
597 
598  friend class ResourceBinder;
599  friend class Renderer::ResourceManager;
600  };
601 
602  typedef base::AllocVector<Resource*> ResourceVector;
603 
604  class ResourceAccessor;
607  class ResourceContainer : public Allocatable {
608  public:
609  ResourceContainer() : resources_(*this) {}
610 
611  private:
612  friend class ResourceAccessor;
613  port::Mutex mutex_;
614  ResourceVector resources_;
615  };
616 
620  class ResourceAccessor {
621  public:
622  explicit ResourceAccessor(ResourceContainer& container) // NOLINT
623  : container_(container),
624  owns_lock_(true) {
625  container_.mutex_.Lock();
626  }
630  ResourceAccessor(ResourceAccessor& other) // NOLINT
631  : container_(other.container_),
632  owns_lock_(true) {
633  other.owns_lock_ = false;
634  }
635  ~ResourceAccessor() {
636  if (owns_lock_)
637  container_.mutex_.Unlock();
638  }
639 
641  ResourceVector& GetResources() { return container_.resources_; }
642 
643  private:
644  ResourceContainer& container_;
646  bool owns_lock_;
647  };
648 
651  explicit ResourceManager(const GraphicsManagerPtr& gm)
652  : gfx::ResourceManager(gm),
653  resource_index_(AcquireOrReleaseResourceIndex(false, 0U)),
654  memory_usage_(*this),
655  resources_to_release_(*this) {
656  memory_usage_.resize(kNumResourceTypes);
657  ResourceAccessor(resources_[kAttributeArray]).GetResources().reserve(128U);
658  ResourceAccessor(resources_[kBufferObject]).GetResources().reserve(128U);
659  ResourceAccessor(resources_[kFramebufferObject]).GetResources().reserve(
660  16U);
661  ResourceAccessor(resources_[kSampler]).GetResources().reserve(32U);
662  ResourceAccessor(resources_[kShaderInputRegistry]).GetResources().reserve(
663  16U);
664  ResourceAccessor(resources_[kShaderProgram]).GetResources().reserve(16U);
665  ResourceAccessor(resources_[kShader]).GetResources().reserve(16U);
666  ResourceAccessor(resources_[kTexture]).GetResources().reserve(128U);
667  }
668 
670  ~ResourceManager() override {}
671 
674  size_t GetResourceIndex() const { return resource_index_; }
675 
677  ResourceAccessor AccessResources(ResourceType type) {
678  ResourceAccessor accessor(resources_[type]);
679  return accessor;
680  }
681 
687  template <typename T>
688  ResourceKey GetResourceKey(ResourceBinder* resource_binder,
689  const ResourceHolder* holder) {
690  return reinterpret_cast<ResourceKey>(this);
691  }
692 
697  template <typename T>
698  std::vector<ResourceKey> GetAllResourceKeys(ResourceBinder* resource_binder) {
699  std::vector<ResourceKey> keys;
700  keys.push_back(GetResourceKey<T>(resource_binder, nullptr));
701  return keys;
702  }
703 
705  template <typename HolderType>
706  typename HolderToResource<HolderType>::ResourceType* GetResource(
707  const HolderType* holder, ResourceBinder* resource_binder,
708  GLuint gl_id = 0);
709 
711  void IncreaseGpuMemoryUsage(ResourceType type, size_t count) {
712  memory_usage_[type].value += count;
713  }
714 
716  void DecreaseGpuMemoryUsage(ResourceType type, size_t count) {
717  DCHECK_LE(count, memory_usage_[type].value.load());
718  memory_usage_[type].value -= count;
719  }
720 
722  size_t GetGpuMemoryUsage(ResourceType type) const {
723  return memory_usage_[type].value.load();
724  }
725 
729  void DisassociateElementBufferFromArrays(BufferResource* resource);
730 
732  void AddResource(Resource* resource) {
733  ResourceAccessor accessor(resources_[resource->GetType()]);
734  ResourceVector& resources = accessor.GetResources();
735  resource->SetIndex(resources.size());
736  resources.push_back(resource);
737  }
738 
740  void MarkForRelease(Resource* resource) {
741  base::LockGuard locker(&release_mutex_);
742  DCHECK(resource);
743  resources_to_release_.push_back(resource);
744  }
745 
747  void DestroyResource(Resource* resource) {
748  DCHECK(resource);
749 
752  ResourceAccessor accessor(resources_[resource->GetType()]);
753  ResourceVector& resources = accessor.GetResources();
754  const size_t num_resources = resources.size();
755  if (num_resources > 1U) {
756  const size_t index = resource->GetIndex();
759  if (resources[index] == resource) {
760  Resource* moved_resource = resources[num_resources - 1U];
761  resources[index] = moved_resource;
762  moved_resource->SetIndex(index);
763  resources.resize(num_resources - 1U);
764  }
765  } else if (num_resources == 1U) {
767  if (resources[0] == resource)
768  resources.clear();
769  }
770  }
771 
774  template <typename HolderType>
775  void ReleaseResources(const HolderType* holder, ResourceBinder* binder) {
776  typedef typename HolderToResource<HolderType>::ResourceType ResourceType;
777  if (holder) {
778  const std::vector<ResourceKey> keys =
779  GetAllResourceKeys<ResourceType>(binder);
780  for (ResourceKey key : keys) {
781  if (ResourceBase* resource =
782  holder->GetResource(resource_index_, key)) {
783  resource->OnDestroyed();
784  }
785  }
786  ReleaseAll(binder);
787  }
788  }
789 
791  void ReleaseTypedResources(ResourceType type) {
792  ResourceAccessor accessor(resources_[type]);
793  ResourceVector& resources = accessor.GetResources();
794  for (auto resource : resources) {
795  resource->OnDestroyed();
796  }
797  }
798 
800  void ReleaseAll(ResourceBinder* resource_binder) {
804  const bool can_make_gl_calls = portgfx::Visual::GetCurrent() != nullptr;
805  while (true) {
806  ResourceVector resources_to_destroy(*this);
807  {
808  base::LockGuard locker(&release_mutex_);
809  for (Resource* resource : resources_to_release_) {
810  resource->Release(can_make_gl_calls);
812  resources_to_destroy.push_back(resource);
813  DestroyResource(resource);
814  }
815  resources_to_release_.clear();
816  }
817 
824  for (Resource* resource : resources_to_destroy)
825  delete resource;
826 
827  {
828  base::LockGuard locker(&release_mutex_);
831  if (resources_to_release_.empty())
832  break;
833  }
834  }
835  }
836 
838  void DestroyAllResources() {
839  const bool can_make_gl_calls = portgfx::Visual::GetCurrent() != nullptr;
840  for (int i = 0; i < kNumResourceTypes; ++i) {
841  ResourceAccessor accessor(resources_[i]);
842  ResourceVector& resources = accessor.GetResources();
843  for (Resource* resource : resources) {
844  resource->Release(can_make_gl_calls);
845  delete resource;
846  }
847  resources.clear();
848  }
849  AcquireOrReleaseResourceIndex(true, resource_index_);
850  }
851 
854  template <typename T> void ProcessDataRequests() {
855  base::LockGuard guard(&this->request_mutex_);
856  std::vector<DataRequest<T> >& requests = *GetDataRequestVector<T>();
857  const size_t request_count = requests.size();
858  std::vector<T> infos(1);
859  for (size_t i = 0; i < request_count; ++i) {
860  T info;
861  FillDataFromRenderer(requests[i].id, &info);
862  FillInfoFromOpenGL(&info);
863  infos[0] = info;
865  requests[i].callback(infos);
866  }
867  requests.clear();
868  }
869 
871  template <typename HolderType, typename InfoType>
872  void ProcessInfoRequests(ResourceContainer* resource_container,
873  ResourceBinder* resource_binder) {
874  base::LockGuard guard(&this->request_mutex_);
875  std::vector<ResourceRequest<HolderType, InfoType> >& requests =
876  *GetResourceRequestVector<HolderType, InfoType>();
877  const size_t request_count = requests.size();
878  for (size_t i = 0; i < request_count; ++i)
879  ProcessInfoRequest<HolderType, InfoType>(requests[i], resource_container,
880  resource_binder);
881  requests.clear();
882  }
883 
885  template <typename HolderType, typename InfoType>
886  void ProcessInfoRequest(const ResourceRequest<HolderType, InfoType>& request,
887  ResourceContainer* resource_container,
888  ResourceBinder* resource_binder) {
889  typedef typename HolderToResource<HolderType>::ResourceType ResourceType;
890  std::vector<InfoType> infos;
891  if (request.holder.Get()) {
896  if (ResourceType* resource =
897  GetResource(request.holder.Get(), resource_binder))
898  AppendResourceInfo(&infos, resource, resource_binder);
899  } else {
901  ResourceAccessor accessor(*resource_container);
902  ResourceVector& resources = accessor.GetResources();
903  const std::vector<ResourceKey> keys =
904  GetAllResourceKeys<ResourceType>(resource_binder);
905  std::unordered_set<ResourceKey> key_set(keys.begin(), keys.end());
906  for (Resource* resource : resources) {
907  if (key_set.find(resource->GetKey()) != key_set.end()) {
908  ResourceType* typed_resource = static_cast<ResourceType*>(resource);
909  AppendResourceInfo(&infos, typed_resource, resource_binder);
910  }
911  }
912  }
914  request.callback(infos);
915  }
916 
919  template <typename InfoType, typename ResourceType>
920  void AppendResourceInfo(std::vector<InfoType>* infos,
921  ResourceType* resource, ResourceBinder* rb) {
922  InfoType info;
923  resource->Bind(rb);
925  info.id = resource->GetId();
926  info.label = resource->GetHolder()->GetLabel();
927  FillInfoFromResource(&info, resource, rb);
929  FillInfoFromOpenGL(&info);
930  resource->Unbind(rb);
931  infos->push_back(info);
932  }
933 
935  template <typename InfoType, typename ResourceType>
936  void FillInfoFromResource(InfoType* info, ResourceType* resource,
937  ResourceBinder* rb) {}
938 
940  template <typename InfoType>
941  void FillDataFromRenderer(GLuint id, InfoType* info);
942 
944  void ProcessResourceInfoRequests(ResourceBinder* resource_binder);
945 
946  private:
949  struct AtomicSizeT {
950  AtomicSizeT() : value(0U) {}
951  AtomicSizeT(const AtomicSizeT& other) : value(other.value.load()) {}
952  AtomicSizeT& operator=(const AtomicSizeT& other) {
953  value = other.value.load();
954  return *this;
955  }
956  std::atomic<size_t> value;
957  };
958 
962  static size_t AcquireOrReleaseResourceIndex(bool is_release, size_t index) {
963  typedef std::set<size_t> IndexSet;
964  ION_DECLARE_SAFE_STATIC_POINTER(port::Mutex, mutex);
965  ION_DECLARE_SAFE_STATIC_POINTER(IndexSet, used_indices);
966  base::LockGuard guard(mutex);
967  size_t new_index = index;
968  IndexSet::const_iterator end = used_indices->end();
969  if (is_release) {
970  IndexSet::iterator it = used_indices->find(index);
971  DCHECK(it != end);
972  used_indices->erase(it);
973  } else {
978  new_index = 0U;
979  while (used_indices->find(new_index) != end)
980  ++new_index;
981  used_indices->insert(new_index);
982  }
983  return new_index;
984  }
985 
987  template <typename HolderType>
988  typename HolderToResource<HolderType>::ResourceType* CreateResource(
989  const HolderType* holder, ResourceBinder* binder, ResourceKey key,
990  GLuint gl_id);
991 
993  size_t resource_index_;
994 
996  ResourceContainer resources_[kNumResourceTypes];
997 
999  base::AllocVector<AtomicSizeT> memory_usage_;
1000 
1005  ResourceVector resources_to_release_;
1006 
1009  port::Mutex release_mutex_;
1010 };
1011 
1013 
1020 
1021 
1022 class Renderer::ResourceBinder : public Allocatable {
1023  public:
1024  typedef base::AllocVector<Uniform> UniformStack;
1025 
1027  struct BufferBinding {
1028  BufferBinding() : buffer(0U), resource(nullptr) {}
1029  GLuint buffer;
1030  BufferResource* resource;
1031  };
1032 
1034  struct ImageUnit {
1035  ImageUnit() : sampler(0U), resource(nullptr) {}
1036  GLuint sampler;
1037  TextureResource* resource;
1038  };
1039 
1043 #if ION_PRODUCTION
1044  class StreamAnnotator : public base::Allocatable {
1045  public:
1046  explicit StreamAnnotator(const GraphicsManagerPtr& gm) {}
1047  void Push(const std::string& label) {}
1048  void Pop() {}
1049  };
1050 #else
1051  class StreamAnnotator : public base::Allocatable {
1052  public:
1053  explicit StreamAnnotator(const GraphicsManagerPtr& gm)
1054  : gm_(gm),
1055  gl_supports_markers_(
1056  gm_->IsFunctionGroupAvailable(GraphicsManager::kDebugMarker)) {}
1057 
1060  void Push(const std::string& marker) {
1061  if (std::ostream* out = gm_->GetTracingStream())
1062  *out << std::string(indent_.length(), '-') << ">" << marker << ":\n";
1063  indent_ += " ";
1064  gm_->SetTracingPrefix(indent_);
1065  if (gl_supports_markers_)
1066  gm_->PushGroupMarker(static_cast<GLsizei>(marker.length()),
1067  marker.c_str());
1068  }
1069 
1071  void Pop() {
1072  if (const size_t length = indent_.length()) {
1073  if (gl_supports_markers_)
1074  gm_->PopGroupMarker();
1075  indent_ = indent_.substr(0, length - 2U);
1076  gm_->SetTracingPrefix(indent_);
1077  }
1078  }
1079 
1080  private:
1081  GraphicsManagerPtr gm_;
1082  std::string indent_;
1083  const bool gl_supports_markers_;
1084  };
1085 #endif
1086 
1087  class InfoRequestGuard {
1088  public:
1089  explicit InfoRequestGuard(ResourceBinder* rb)
1090  : rb_(rb) {
1091  rb_->processing_info_requests_ = true;
1092  }
1093  ~InfoRequestGuard() {
1094  rb_->processing_info_requests_ = false;
1095  }
1096 
1097  private:
1098  ResourceBinder* rb_;
1099  };
1100 
1102  explicit ResourceBinder(const GraphicsManagerPtr& gm)
1103  : graphics_manager_(gm),
1104  stream_annotator_(new (GetAllocator()) StreamAnnotator(gm)),
1105  image_units_(*this),
1106  texture_last_bindings_(*this),
1107  active_image_unit_(kInvalidGluint),
1108  active_framebuffer_(kInvalidGluint),
1109  active_framebuffer_resource_(nullptr),
1110  active_shader_id_(0U),
1111  active_shader_resource_(nullptr),
1112  active_vertex_array_(0U),
1113  active_vertex_array_resource_(nullptr),
1114  current_shader_program_(nullptr),
1115  vertex_array_keys_(*this),
1116  gl_state_table_(new (GetAllocator()) StateTable(0, 0)),
1117  client_state_table_(new (GetAllocator()) StateTable(0, 0)),
1118  traversal_state_tables_(*this),
1119  current_traversal_index_(0U),
1120  processing_info_requests_(false) {
1121  memset(saved_ids_, 0, sizeof(saved_ids_));
1122  saved_state_table_ = new (GetAllocator()) StateTable();
1123 
1125  if (gm->GetGlApiStandard() == GraphicsManager::kDesktop) {
1127  if (gm->GetGlProfileType() != GraphicsManager::kCoreProfile)
1128  gm->Enable(GL_POINT_SPRITE);
1129  gm->Enable(GL_PROGRAM_POINT_SIZE);
1130  }
1131 
1134 
1136  const int max_image_units = GetGraphicsManager()->GetCapabilityValue<int>(
1138  image_units_.resize(max_image_units);
1139  texture_manager_.reset(new (GetAllocator())
1140  TextureManager(max_image_units));
1141  DCHECK(texture_manager_.get());
1142 
1143  traversal_state_tables_.resize(16);
1144  for (size_t i = 0; i < 16U; ++i)
1145  traversal_state_tables_[i] = new(GetAllocator()) StateTable;
1146  }
1147 
1148  ~ResourceBinder() override {}
1149 
1152  GetGraphicsManager()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
1153  GetSavedId(Renderer::kSaveFramebuffer));
1154  }
1155 
1157  const GraphicsManagerPtr& GetGraphicsManager() const {
1158  return graphics_manager_;
1159  }
1160 
1163  TextureManager* GetTextureManager() const { return texture_manager_.get(); }
1164 
1167  ResourceManager* GetResourceManager() const { return resource_manager_; }
1168  void SetResourceManager(ResourceManager* manager) {
1169  resource_manager_ = manager;
1170  }
1171 
1173  StreamAnnotator* GetStreamAnnotator() const {
1174  return stream_annotator_.get();
1175  }
1176 
1179  return current_fbo_.Acquire();
1180  }
1181 
1183  void SetCurrentFramebuffer(const FramebufferObjectPtr& fbo) {
1184  current_fbo_ = base::WeakReferentPtr<FramebufferObject>(fbo);
1185  }
1186 
1188  ShaderProgramResource* GetActiveShaderProgram() const {
1189  return active_shader_resource_;
1190  }
1191 
1193  FramebufferResource* GetActiveFramebuffer() const {
1194  return active_framebuffer_resource_;
1195  }
1196 
1198  VertexArrayResource* GetActiveVertexArray() const {
1199  return active_vertex_array_resource_;
1200  }
1201 
1206  void SetActiveVertexArray(VertexArrayResource* resource) {
1207  active_vertex_array_resource_ = resource;
1208  }
1209 
1212  StateTable* GetStateTable() const { return gl_state_table_.Get(); }
1213 
1215  void BindBuffer(BufferObject::Target target, GLuint id,
1216  BufferResource* resource);
1217 
1219  void BindFramebuffer(GLuint id, FramebufferResource* fbo);
1220 
1223  bool BindProgram(GLuint id, ShaderProgramResource* resource);
1224 
1227  void BindSamplerToUnit(GLuint id, GLuint unit) {
1228  DCHECK_LT(unit, image_units_.size());
1229  if (!id || id != image_units_[unit].sampler) {
1230  image_units_[unit].sampler = id;
1231  GetGraphicsManager()->BindSampler(unit, id);
1232  }
1233  }
1234 
1236  void ActivateUnit(GLuint unit);
1237 
1240  void BindTextureToUnit(TextureResource* resource, GLuint unit);
1241 
1243  bool WasTextureEvicted(TextureResource* resource) {
1244  auto found = texture_last_bindings_.find(resource);
1245  if (found == texture_last_bindings_.end())
1246  return false;
1247  if (image_units_[found->second].resource == resource)
1248  return false;
1249  return true;
1250  }
1253  int GetLastBoundUnit(TextureResource* resource) {
1254  auto found = texture_last_bindings_.find(resource);
1255  if (found != texture_last_bindings_.end())
1256  return found->second;
1257  return 0;
1258  }
1260  void ClearAssignedImageUnit(TextureResource* resource) {
1261  texture_last_bindings_.erase(resource);
1262  }
1263 
1265  void BindVertexArray(GLuint id, VertexArrayResource* resource);
1266 
1268  void ClearBufferBinding(BufferObject::Target target, GLuint id) {
1269  if (!id || id == active_buffers_[target].buffer) {
1270  active_buffers_[target].buffer = 0;
1271  active_buffers_[target].resource = nullptr;
1272  }
1273  }
1274 
1276  void ClearFramebufferBinding(GLuint id) {
1277  if (!id || id == active_framebuffer_) {
1278  active_framebuffer_ = kInvalidGluint;
1279  active_framebuffer_resource_ = nullptr;
1280  }
1281  }
1282 
1284  void ClearProgramBinding(GLuint id) {
1285  if (!id || id == active_shader_id_) {
1286  active_shader_id_ = 0;
1287  active_shader_resource_ = nullptr;
1288  }
1289  }
1290 
1292  void ClearSamplerBindings(GLuint id) {
1293  const size_t count = image_units_.size();
1294  for (size_t i = 0; i < count; ++i)
1295  if (id == image_units_[i].sampler)
1296  image_units_[i].sampler = 0;
1297  }
1298 
1301  void ClearTextureBinding(GLuint id, GLuint unit);
1302 
1304  void ClearVertexArrayBinding(GLuint id);
1305 
1307  void ClearNonFramebufferCachedBindings();
1308 
1309  template <typename HolderType>
1310  void BindResource(const HolderType* holder) {
1311  if (holder) {
1312  if (typename HolderToResource<HolderType>::ResourceType* resource =
1313  resource_manager_->GetResource(holder, this)) {
1315  resource->Update(this);
1316  }
1317  }
1318  }
1319 
1324  struct CreateOrUpdateOp {
1325  template <typename HolderType>
1326  static void Process(ResourceBinder* rb, const HolderType* holder,
1327  GLuint gl_id) {
1328  if (holder) {
1329  typename HolderToResource<HolderType>::ResourceType* resource =
1330  rb->GetResourceManager()->GetResource(holder, rb, gl_id);
1331  if (resource) {
1336  resource->UnbindAll();
1337 
1339  if (resource->AnyModifiedBitsSet())
1340  resource->Update(rb);
1341  }
1342  }
1343  }
1344  };
1345 
1348  struct RequestUpdateOp {
1349  template <typename HolderType>
1350  static void Process(ResourceBinder* rb, const HolderType* holder,
1351  GLuint gl_id) {
1352  if (holder) {
1353  Renderer::SetResourceHolderBit(holder,
1355  holder->Notify();
1356  }
1357  }
1358  };
1359 
1363  template <typename Operation, typename HolderType>
1364  struct OperationImpl {
1365  static void Process(ResourceBinder* rb, const HolderType* holder,
1366  GLuint gl_id) {
1367  Operation::Process(rb, holder, gl_id);
1368  }
1369  };
1370 
1372  template <typename Operation>
1373  struct OperationImpl<Operation, AttributeArray> {
1374  static void Process(ResourceBinder* rb, const AttributeArray* aa,
1375  GLuint gl_id) {
1376  if (aa == nullptr) return;
1378  std::set<BufferObject*> buffers;
1379  const size_t buffer_attribute_count = aa->GetBufferAttributeCount();
1380  for (size_t i = 0; i < buffer_attribute_count; ++i) {
1381  const Attribute& a = aa->GetBufferAttribute(i);
1382  if (BufferObject* bo =
1383  a.GetValue<BufferObjectElement>().buffer_object.Get()) {
1385  if (buffers.find(bo) == buffers.end()) {
1386  Operation::Process(rb, bo, gl_id);
1387  buffers.insert(bo);
1388  }
1389  }
1390  }
1391  GraphicsManager* gm = rb->GetGraphicsManager().Get();
1392  if (gm->IsFunctionGroupAvailable(GraphicsManager::kVertexArrays))
1393  Operation::Process(rb, aa, gl_id);
1394  else
1395  Operation::Process(rb,
1396  reinterpret_cast<const AttributeArrayEmulator*>(aa), gl_id);
1397  }
1398  };
1399 
1403  template <typename Operation, typename HolderType>
1404  void Process(const HolderType* holder, GLuint gl_id) {
1405  OperationImpl<Operation, HolderType>::Process(this, holder, gl_id);
1406  }
1407 
1412  template <typename Operation>
1413  void Traverse(const NodePtr& node, ShaderProgram* default_shader);
1414 
1416  template <typename Operation>
1417  void VisitShape(const ShapePtr& shape);
1418 
1421  void ProcessStateTable(const StateTablePtr& state_table);
1422 
1427  const ImagePtr ReadImage(const math::Range2i& range, Image::Format format,
1428  const base::AllocatorPtr& allocator);
1429 
1431  void SendUniform(const Uniform& uniform, int location, GraphicsManager* gm);
1432 
1435  void PushUniforms(const Node* node,
1436  const base::AllocVector<Uniform>& uniforms);
1439  void PopUniforms(const base::AllocVector<Uniform>& uniforms);
1440 
1442  GLint* GetSavedId(Renderer::Flag flag) {
1444  DCHECK_LE(flag, kSaveVertexArray);
1445  return &saved_ids_[flag - kSaveActiveTexture];
1446  }
1447 
1449  size_t GetImageUnitCount() const { return image_units_.size(); }
1451  void SetImageUnitRange(const Range1i& units) {
1452  const int max_image_units = GetGraphicsManager()->GetCapabilityValue<int>(
1455  const GLuint count = static_cast<GLuint>(GetImageUnitCount());
1456  for (GLuint i = max_image_units; i < count; ++i) {
1457  ClearTextureBinding(0U, i);
1458  }
1459  ClearSamplerBindings(0U);
1460  texture_manager_->SetUnitRange(units);
1461  }
1462 
1465  const math::Range1ui& range_in);
1467 
1469  void DrawScene(const NodePtr& node, const Flags& flags,
1470  ShaderProgram* default_shader);
1471 
1474  bool IsProcessingInfoRequests() const { return processing_info_requests_; }
1475 
1479  ResourceKey GetVertexArrayKey() {
1480  auto key_iterator = vertex_array_keys_.find(GetActiveShaderProgram());
1481  if (key_iterator == vertex_array_keys_.end()) {
1482  return reinterpret_cast<ResourceKey>(
1483  &*vertex_array_keys_.insert(GetActiveShaderProgram()).first);
1484  } else {
1485  return reinterpret_cast<ResourceKey>(&*key_iterator);
1486  }
1487  }
1488  std::vector<ResourceKey> GetAllVertexArrayKeys() {
1489  std::vector<ResourceKey> keys;
1490  for (const auto &i : vertex_array_keys_) {
1491  keys.push_back(reinterpret_cast<ResourceKey>(&i));
1492  }
1493  return keys;
1494  }
1495 
1498  void EraseVertexArrayKey(ShaderProgramResource *shader) {
1499  vertex_array_keys_.erase(shader);
1500  }
1501 
1502  private:
1505 
1507  void DrawNode(const Node& node, GraphicsManager* gm);
1509  void DrawShape(const Shape& shape, GraphicsManager* gm);
1511  void DrawIndexedShape(const Shape& shape, const IndexBuffer& ib,
1512  GraphicsManager* gm);
1514  void DrawNonindexedShape(const Shape& shape, size_t vertex_count,
1515  GraphicsManager* gm);
1516 
1519  void MarkAttachmentImplicitlyChanged(
1520  const FramebufferObject::Attachment& attachment);
1521 
1524  template <typename Operation>
1525  void Visit(const NodePtr& node);
1526 
1528  GraphicsManagerPtr graphics_manager_;
1529 
1531  std::unique_ptr<StreamAnnotator> stream_annotator_;
1532 
1536  std::unique_ptr<TextureManager> texture_manager_;
1537 
1539  base::WeakReferentPtr<FramebufferObject> current_fbo_;
1540 
1542  base::AllocVector<ImageUnit> image_units_;
1544  base::AllocUnorderedMap<TextureResource*, GLuint> texture_last_bindings_;
1545  GLuint active_image_unit_;
1546 
1548  std::array<BufferBinding, 4> active_buffers_;
1549 
1553  GLuint active_framebuffer_;
1554  FramebufferResource* active_framebuffer_resource_;
1555 
1557  GLuint active_shader_id_;
1558  ShaderProgramResource* active_shader_resource_;
1559 
1561  GLuint active_vertex_array_;
1562  VertexArrayResource* active_vertex_array_resource_;
1563 
1566  GLint
1568  StateTablePtr saved_state_table_;
1569 
1572  ResourceManager* resource_manager_;
1573 
1575  ShaderProgram* current_shader_program_;
1576 
1582  base::AllocSet<ShaderProgramResource*> vertex_array_keys_;
1583 
1585  StateTablePtr gl_state_table_;
1587  StateTablePtr client_state_table_;
1589  base::AllocVector<StateTablePtr> traversal_state_tables_;
1590  size_t current_traversal_index_;
1591 
1593  bool processing_info_requests_;
1594 
1595  friend class InfoRequestGuard;
1596 };
1597 
1600 template <>
1601 ResourceKey Renderer::ResourceManager::GetResourceKey<
1602  Renderer::VertexArrayResource>(ResourceBinder* resource_binder,
1603  const ResourceHolder* holder) {
1604  return resource_binder->GetVertexArrayKey();
1605 }
1606 template <>
1607 std::vector<ResourceKey> Renderer::ResourceManager::GetAllResourceKeys<
1608  Renderer::VertexArrayResource>(ResourceBinder* resource_binder) {
1609  return resource_binder->GetAllVertexArrayKeys();
1610 }
1611 
1612 template <>
1613 ResourceKey Renderer::ResourceManager::GetResourceKey<
1614  Renderer::VertexArrayEmulatorResource>(ResourceBinder* resource_binder,
1615  const ResourceHolder* holder) {
1616  return resource_binder->GetVertexArrayKey();
1617 }
1618 template <>
1619 std::vector<ResourceKey> Renderer::ResourceManager::GetAllResourceKeys<
1620  Renderer::VertexArrayEmulatorResource>(ResourceBinder* resource_binder) {
1621  return resource_binder->GetAllVertexArrayKeys();
1622 }
1623 
1624 template <>
1625 ResourceKey Renderer::ResourceManager::GetResourceKey<
1626  Renderer::ShaderInputRegistryResource>(ResourceBinder* resource_binder,
1627  const ResourceHolder* holder) {
1628  return reinterpret_cast<ResourceKey>(resource_binder);
1629 }
1630 
1631 template <>
1632 ResourceKey Renderer::ResourceManager::GetResourceKey<
1633  Renderer::FramebufferResource>(ResourceBinder* resource_binder,
1634  const ResourceHolder* holder) {
1635  return reinterpret_cast<ResourceKey>(resource_binder);
1636 }
1637 
1638 template <>
1639 ResourceKey Renderer::ResourceManager::GetResourceKey<
1640  Renderer::ShaderProgramResource>(ResourceBinder* resource_binder,
1641  const ResourceHolder* holder) {
1642  ShaderProgram* program = const_cast<ShaderProgram*>(
1643  static_cast<const ShaderProgram*>(holder));
1646  program->SetConcurrent(program->IsConcurrent());
1647  if (program->IsConcurrent()) {
1648  return reinterpret_cast<ResourceKey>(resource_binder);
1649  } else {
1650  return reinterpret_cast<ResourceKey>(this);
1651  }
1652 }
1653 template <>
1654 std::vector<ResourceKey> Renderer::ResourceManager::GetAllResourceKeys<
1655  Renderer::ShaderProgramResource>(ResourceBinder* resource_binder) {
1656  std::vector<ResourceKey> keys;
1657  keys.push_back(reinterpret_cast<ResourceKey>(resource_binder));
1658  keys.push_back(reinterpret_cast<ResourceKey>(this));
1659  return keys;
1660 }
1661 
1662 void Renderer::ResourceManager::ProcessResourceInfoRequests(
1663  ResourceBinder* resource_binder) {
1664  ResourceBinder::InfoRequestGuard guard(resource_binder);
1665 
1667  ProcessInfoRequests<AttributeArray, ArrayInfo>(&resources_[kAttributeArray],
1668  resource_binder);
1669  ProcessInfoRequests<BufferObject, BufferInfo>(&resources_[kBufferObject],
1670  resource_binder);
1671  ProcessInfoRequests<FramebufferObject, FramebufferInfo>(
1672  &resources_[kFramebufferObject], resource_binder);
1673  ProcessInfoRequests<Sampler, SamplerInfo>(&resources_[kSampler],
1674  resource_binder);
1675  ProcessInfoRequests<ShaderProgram, ProgramInfo>(&resources_[kShaderProgram],
1676  resource_binder);
1677  ProcessInfoRequests<Shader, ShaderInfo>(&resources_[kShader],
1678  resource_binder);
1679  ProcessInfoRequests<TextureBase, TextureInfo>(&resources_[kTexture],
1680  resource_binder);
1681  ProcessDataRequests<PlatformInfo>();
1682  ProcessDataRequests<TextureImageInfo>();
1683 }
1684 
1687 #if ION_PRODUCTION
1688 class Renderer::ScopedLabel {
1689  public:
1690  ScopedLabel(ResourceBinder* binder, const void* address,
1691  const std::string& label) {}
1692 };
1693 #else
1694 class Renderer::ScopedLabel {
1695  public:
1696  ScopedLabel(ResourceBinder* rb, const void* address,
1697  const std::string& label)
1698  : annotator_(rb->GetStreamAnnotator()),
1699  needs_pop_(false) {
1700  if (rb->GetGraphicsManager()->GetTracingStream() && label.length()) {
1701  annotator_->Push(label + " [" + base::ValueToString(address) + "]");
1702  needs_pop_ = true;
1703  }
1704  }
1705  ~ScopedLabel() {
1706  if (needs_pop_)
1707  annotator_->Pop();
1708  }
1709 
1710  private:
1711  ResourceBinder::StreamAnnotator* annotator_;
1712  bool needs_pop_;
1713 };
1714 #endif
1715 
1717 
1728 
1729 
1730 template <int NumModifiedBits>
1731 class Renderer::Resource : public Renderer::ResourceManager::Resource {
1732  public:
1733  class ScopedResourceLabel : public ScopedLabel {
1734  public:
1735  ScopedResourceLabel(Resource* resource, ResourceBinder* binder)
1736  : ScopedLabel(binder, resource->GetHolder(),
1737  resource->GetHolder()->GetLabel()) {}
1738  };
1739 
1740  ~Resource() override { DetachFromHolder(); }
1741 
1742  bool AnyModifiedBitsSet() const { return modified_bits_.any(); }
1743 
1744  void OnDestroyed() override {
1746  DetachFromHolder();
1747  if (GetResourceManager())
1748  GetResourceManager()->MarkForRelease(this);
1749  }
1750 
1752  GLuint GetId() const { return id_; }
1753 
1754  protected:
1755  typedef Renderer::Resource<NumModifiedBits> BaseResourceType;
1756 
1757  Resource(ResourceManager* rm, const ResourceHolder& holder, ResourceKey key,
1758  GLuint id)
1759  : Renderer::ResourceManager::Resource(rm, &holder, key),
1760  id_(id),
1761  resource_owns_gl_id_(id == 0U) {
1763  SetModifiedBits();
1766  modified_bits_.reset(ResourceHolder::kResourceChanged);
1767  }
1768 
1769  GraphicsManager* GetGraphicsManager() const {
1771  }
1772 
1774  bool HasHolder() const { return GetHolder() != nullptr; }
1775 
1776  void Release(bool can_make_gl_calls) override { DetachFromHolder(); }
1777 
1779  void OnChanged(const int bit) override { modified_bits_.set(bit); }
1780 
1781  void ResetModifiedBit(int bit) { modified_bits_.reset(bit); }
1782 
1783  void ResetModifiedBits() { modified_bits_.reset(); }
1784 
1785  void SetModifiedBit(int bit) { modified_bits_.set(bit); }
1786 
1787  void SetModifiedBits() { modified_bits_.set(); }
1788 
1789  bool TestModifiedBit(int bit) const { return modified_bits_.test(bit); }
1790 
1793  bool TestModifiedBitRange(int low_bit, int high_bit) const {
1794  std::bitset<NumModifiedBits> mask;
1796  mask.set();
1799  mask <<= high_bit + 1 - low_bit;
1802  mask.flip();
1804  mask <<= low_bit;
1806  return (mask & modified_bits_).any();
1807  }
1808 
1809  const std::bitset<NumModifiedBits>& GetBits() const { return modified_bits_; }
1810 
1811  friend class ResourceBinder;
1812 
1814  GLuint id_;
1816  const bool resource_owns_gl_id_;
1817 
1818  private:
1819  void DetachFromHolder() {
1820  if (HasHolder()) {
1821  const ResourceHolder* holder = GetHolder();
1822  const size_t index = GetResourceManager()->GetResourceIndex();
1826  if (holder->GetResource(index, GetKey()) == this) {
1828  holder->Notify();
1829  holder->SetResource(index, GetKey(), nullptr);
1830  }
1831  }
1832  }
1833 
1834  std::bitset<NumModifiedBits> modified_bits_;
1835 };
1836 
1838 
1843 
1844 
1845 class Renderer::SamplerResource : public Resource<Sampler::kNumChanges> {
1846  public:
1847  SamplerResource(ResourceBinder* rb, ResourceManager* rm,
1848  const Sampler& sampler, ResourceKey key, GLuint id)
1849  : Renderer::Resource<Sampler::kNumChanges>(rm, sampler, key, id) {}
1850 
1851  ~SamplerResource() override {
1852  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
1853  }
1854 
1855  void Release(bool can_make_gl_calls) override;
1856  void Update(ResourceBinder* rb) override;
1857  ResourceType GetType() const override { return kSampler; }
1858 
1861  void Bind(ResourceBinder* rb) { Update(rb); }
1862  void Unbind(ResourceBinder* rb) override;
1863 
1865  void BindToUnit(GLuint unit, ResourceBinder* rb);
1866 
1867  const Sampler& GetSampler() const {
1868  return static_cast<const Sampler&>(*GetHolder());
1869  }
1870 };
1871 
1872 void Renderer::SamplerResource::Update(ResourceBinder* rb) {
1873  if (GetGraphicsManager()->IsFunctionGroupAvailable(
1875  const Sampler& sampler = GetSampler();
1876 
1877  if (AnyModifiedBitsSet()) {
1878  ScopedResourceLabel label(this, rb);
1880  GraphicsManager* gm = GetGraphicsManager();
1881  DCHECK(gm);
1882  if (!id_) gm->GenSamplers(1, &id_);
1883  if (id_) {
1886 
1888  if (TestModifiedBit(Sampler::kMaxAnisotropyChanged) &&
1889  gm->IsExtensionSupported("texture_filter_anisotropic")) {
1890  const float aniso =
1891  std::min(sampler.GetMaxAnisotropy(),
1892  gm->GetCapabilityValue<float>(
1894  gm->SamplerParameterf(id_, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
1895  }
1896  if (TestModifiedBit(Sampler::kMinFilterChanged))
1897  gm->SamplerParameteri(
1898  id_, GL_TEXTURE_MIN_FILTER,
1899  base::EnumHelper::GetConstant(sampler.GetMinFilter()));
1900  if (TestModifiedBit(Sampler::kMagFilterChanged))
1901  gm->SamplerParameteri(
1902  id_, GL_TEXTURE_MAG_FILTER,
1903  base::EnumHelper::GetConstant(sampler.GetMagFilter()));
1904  if (TestModifiedBit(Sampler::kWrapSChanged))
1905  gm->SamplerParameteri(
1906  id_, GL_TEXTURE_WRAP_S,
1907  base::EnumHelper::GetConstant(sampler.GetWrapS()));
1908  if (TestModifiedBit(Sampler::kWrapTChanged))
1909  gm->SamplerParameteri(
1910  id_, GL_TEXTURE_WRAP_T,
1911  base::EnumHelper::GetConstant(sampler.GetWrapT()));
1912  if (TestModifiedBit(Sampler::kCompareFunctionChanged))
1913  gm->SamplerParameteri(
1914  id_, GL_TEXTURE_COMPARE_FUNC,
1915  base::EnumHelper::GetConstant(sampler.GetCompareFunction()));
1916  if (TestModifiedBit(Sampler::kCompareModeChanged))
1917  gm->SamplerParameteri(
1918  id_, GL_TEXTURE_COMPARE_MODE,
1919  sampler.GetCompareMode() == Sampler::kCompareToTexture
1920  ? GL_COMPARE_REF_TO_TEXTURE
1921  : GL_NONE);
1922  if (TestModifiedBit(Sampler::kMaxLodChanged))
1923  gm->SamplerParameterf(id_, GL_TEXTURE_MAX_LOD, sampler.GetMaxLod());
1924  if (TestModifiedBit(Sampler::kMinLodChanged))
1925  gm->SamplerParameterf(id_, GL_TEXTURE_MIN_LOD, sampler.GetMinLod());
1926  if (TestModifiedBit(Sampler::kWrapRChanged))
1927  gm->SamplerParameteri(
1928  id_, GL_TEXTURE_WRAP_R,
1929  base::EnumHelper::GetConstant(sampler.GetWrapR()));
1930 
1931  ResetModifiedBits();
1932  } else {
1933  LOG(ERROR) << "***ION: Unable to create sampler object";
1934  }
1935  }
1936  }
1937 }
1938 
1939 void Renderer::SamplerResource::BindToUnit(GLuint unit, ResourceBinder* rb) {
1940  Update(rb);
1941  if (id_)
1942  rb->BindSamplerToUnit(id_, unit);
1943 }
1944 
1945 void Renderer::SamplerResource::Unbind(ResourceBinder* rb) {
1946  if (id_ && rb)
1947  rb->ClearSamplerBindings(id_);
1948 }
1949 
1950 void Renderer::SamplerResource::Release(bool can_make_gl_calls) {
1951  BaseResourceType::Release(can_make_gl_calls);
1952  if (id_) {
1953  UnbindAll();
1954  if (resource_owns_gl_id_ && can_make_gl_calls)
1955  GetGraphicsManager()->DeleteSamplers(1, &id_);
1956  id_ = 0;
1957  }
1958 }
1959 
1961 
1966 
1967 
1970 class Renderer::TextureResource : public Resource<CubeMapTexture::kNumChanges> {
1971  public:
1972  TextureResource(ResourceBinder* rb, ResourceManager* rm,
1973  const TextureBase& texture, ResourceKey key, GLuint id)
1974  : Renderer::Resource<CubeMapTexture::kNumChanges>(rm, texture, key, id),
1975  gl_target_(0),
1976  last_uploaded_components_(0U),
1977  auto_mipmapping_enabled_(false),
1978  max_anisotropy_(0.f),
1979  min_lod_(0.f),
1980  max_lod_(0.f),
1981  compare_function_(base::InvalidEnumValue<Sampler::CompareFunction>()),
1982  compare_mode_(base::InvalidEnumValue<Sampler::CompareMode>()),
1983  min_filter_(base::InvalidEnumValue<Sampler::FilterMode>()),
1984  mag_filter_(base::InvalidEnumValue<Sampler::FilterMode>()),
1985  wrap_r_(base::InvalidEnumValue<Sampler::WrapMode>()),
1986  wrap_s_(base::InvalidEnumValue<Sampler::WrapMode>()),
1987  wrap_t_(base::InvalidEnumValue<Sampler::WrapMode>()),
1988  multisample_enabled_by_renderer_(false) {
1989  DCHECK_GE(static_cast<int>(CubeMapTexture::kNumChanges),
1990  static_cast<int>(Texture::kNumChanges));
1991  }
1992 
1993  ~TextureResource() override {
1994  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
1995  }
1996 
1998  void Update(ResourceBinder* rb) override;
1999  void Release(bool can_make_gl_calls) override;
2000 
2001  ResourceType GetType() const override { return kTexture; }
2002 
2003  GLenum GetGlTarget() const { return gl_target_; }
2004 
2005  template <typename T> const T& GetTexture() const {
2006  return static_cast<const T&>(*(this->GetHolder()));
2007  }
2008 
2011  void Bind(ResourceBinder* rb);
2013  void BindToUnit(ResourceBinder* rb, GLuint unit);
2014  void Unbind(ResourceBinder* rb) override;
2015 
2016  void OnDestroyed() override {
2017  UnbindAll();
2018  Renderer::Resource<CubeMapTexture::kNumChanges>::OnDestroyed();
2019  }
2020 
2022  GLuint ObtainImageUnit(ResourceBinder* rb, const void* assoc, int old_unit) {
2025  const int unit = rb->GetTextureManager()->GetUnit(assoc, old_unit);
2026  return static_cast<GLuint>(unit);
2027  }
2028 
2030  bool SetMultisampleEnabledByRenderer(bool multisample_enabled_by_renderer) {
2031  const bool changed = multisample_enabled_by_renderer_ !=
2032  multisample_enabled_by_renderer;
2033  multisample_enabled_by_renderer_ = multisample_enabled_by_renderer;
2034  return changed;
2035  }
2036 
2037  protected:
2039  bool IsComplete() const;
2040 
2042  void UpdateCubeMapImageState(GraphicsManager* gm);
2043  void UpdateTextureImageState(GraphicsManager* gm, bool multisample,
2044  bool multisample_changed);
2045 
2047  void CreateImmutableTexture(const Image& image, const bool multisample,
2048  const size_t samples,
2049  const bool fixed_sample_locations, size_t levels,
2050  GraphicsManager* gm);
2051 
2052  bool CheckImage(const Image& image, const TextureBase& texture);
2053  void UploadImage(const Image& image, GLenum target, GLint level,
2054  int samples, bool fixed_sample_locations,
2055  bool is_full_image, const Point3ui& offset,
2056  GraphicsManager* gm);
2057  void UpdateMemoryUsage(TextureBase::TextureType type);
2058  void UpdateMipmapGeneration(const Sampler& sampler, bool image_has_changed,
2059  GraphicsManager* gm);
2060  bool UpdateMipmap0Image(const Image& image, const TextureBase& texture,
2061  const size_t mipmap_count, GLenum target,
2062  int mipmap_changed_bit, GraphicsManager* gm,
2063  size_t* required_levels, bool multisample_changed);
2064  bool UpdateImage(const Image& image0, const Image& image,
2065  const TextureBase& texture, GLenum target, int level,
2066  GraphicsManager* gm);
2067  void UpdateState(const TextureBase& texture, ResourceBinder* rb, GLuint unit);
2068  void UpdateSamplerState(const Sampler& sampler, GraphicsManager* gm);
2069  void UpdateSubImages(const base::AllocVector<Texture::SubImage>& images,
2070  GLenum target, GraphicsManager* gm);
2071  void UpdateTextureState(const TextureBase& texture, GraphicsManager* gm);
2072 
2073  GLenum gl_target_;
2074  int last_uploaded_components_;
2075 
2077  bool auto_mipmapping_enabled_;
2078  float max_anisotropy_;
2079  float min_lod_;
2080  float max_lod_;
2081  Sampler::CompareFunction compare_function_;
2082  Sampler::CompareMode compare_mode_;
2083  Sampler::FilterMode min_filter_;
2084  Sampler::FilterMode mag_filter_;
2085  Sampler::WrapMode wrap_r_;
2086  Sampler::WrapMode wrap_s_;
2087  Sampler::WrapMode wrap_t_;
2088 
2090  bool multisample_enabled_by_renderer_;
2091 
2092  private:
2094  void UpdateWithUnit(ResourceBinder* rb, GLuint unit);
2095 
2097  void UpdateTextureTarget(GraphicsManager* gm, const bool multisample) {
2099  const TextureBase& base = GetTexture<TextureBase>();
2100  Image* image = base.GetImmutableImage().Get();
2101  if (base.GetTextureType() == TextureBase::kCubeMapTexture) {
2102  if (image) {
2103  UpdateCubeMapTextureTypeFromImage(*image);
2104  } else {
2105  const CubeMapTexture& texture = GetTexture<CubeMapTexture>();
2106  if (texture.HasImage(CubeMapTexture::kNegativeX, 0U)) {
2107  UpdateCubeMapTextureTypeFromImage(
2108  *texture.GetImage(CubeMapTexture::kNegativeX, 0U));
2109  }
2110  }
2111  } else {
2112  if (image) {
2113  UpdateTextureTypeFromImage(*image, multisample);
2114  } else {
2115  const Texture& texture = GetTexture<Texture>();
2116  if (texture.HasImage(0U))
2117  UpdateTextureTypeFromImage(*texture.GetImage(0U), multisample);
2118  }
2119  }
2120  }
2121 
2124  void UpdateTextureTypeFromImage(const Image& image, bool multisample) {
2125  if (image.GetType() == Image::kEgl) {
2126  gl_target_ = GL_TEXTURE_2D;
2127  } else if (image.GetType() == Image::kExternalEgl) {
2128  gl_target_ = GL_TEXTURE_EXTERNAL_OES;
2129  } else {
2130  if (image.GetDimensions() == Image::k2d) {
2131  if (image.GetType() == Image::kArray) {
2132  gl_target_ = GL_TEXTURE_1D_ARRAY;
2133  } else if (image.GetType() == Image::kDense) {
2134  if (multisample) {
2135  gl_target_ = GL_TEXTURE_2D_MULTISAMPLE;
2136  } else {
2137  gl_target_ = GL_TEXTURE_2D;
2138  }
2139  }
2140  } else if (image.GetDimensions() == Image::k3d) {
2141  if (image.GetType() == Image::kArray) {
2142  if (multisample) {
2143  gl_target_ = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
2144  } else {
2145  gl_target_ = GL_TEXTURE_2D_ARRAY;
2146  }
2147  } else if (image.GetType() == Image::kDense) {
2148  gl_target_ = GL_TEXTURE_3D;
2149  }
2150  }
2151  }
2152  }
2153 
2155  void UpdateCubeMapTextureTypeFromImage(const Image& image) {
2156  if (image.GetType() == Image::kEgl) {
2157  gl_target_ = GL_TEXTURE_2D;
2158  } else if (image.GetType() == Image::kExternalEgl) {
2159  gl_target_ = GL_TEXTURE_EXTERNAL_OES;
2160  } else {
2161  if (image.GetDimensions() == Image::k3d ||
2162  image.GetType() == Image::kArray) {
2163  gl_target_ = GL_TEXTURE_CUBE_MAP_ARRAY;
2164  } else if (image.GetType() == Image::kDense) {
2165  gl_target_ = GL_TEXTURE_CUBE_MAP;
2166  }
2167  }
2168  }
2169 };
2170 
2171 void Renderer::TextureResource::Bind(ResourceBinder* rb) {
2172  const GLuint unit = ObtainImageUnit(rb, this, rb->GetLastBoundUnit(this));
2173  BindToUnit(rb, unit);
2174 }
2175 
2176 void Renderer::TextureResource::BindToUnit(ResourceBinder* rb, GLuint unit) {
2177  UpdateWithUnit(rb, unit);
2178  if (id_) {
2179  ScopedResourceLabel label(this, rb);
2180  rb->BindTextureToUnit(this, unit);
2181  Sampler* sampler = GetTexture<TextureBase>().GetSampler().Get();
2182  if (sampler &&
2183  GetGraphicsManager()->IsFunctionGroupAvailable(
2187  SamplerResource* sr = GetResource(sampler, rb);
2188  DCHECK(sr);
2189  sr->BindToUnit(unit, rb);
2190  }
2191  }
2192 }
2193 
2194 void Renderer::TextureResource::Update(ResourceBinder* rb) {
2195  if ((AnyModifiedBitsSet() || rb->WasTextureEvicted(this)) && IsComplete()) {
2196  const GLuint unit = ObtainImageUnit(rb, this,
2197  rb->GetLastBoundUnit(this));
2198  UpdateWithUnit(rb, unit);
2199  }
2200 }
2201 
2202 void Renderer::TextureResource::UpdateWithUnit(ResourceBinder* rb,
2203  GLuint unit) {
2204  if ((AnyModifiedBitsSet() || rb->WasTextureEvicted(this)) && IsComplete())
2205  UpdateState(GetTexture<TextureBase>(), rb, unit);
2206 }
2207 
2208 bool Renderer::TextureResource::CheckImage(const Image& image,
2209  const TextureBase& texture) {
2211  if (Sampler* sampler = texture.GetSampler().Get()) {
2212  if (!math::IsPowerOfTwo(image.GetWidth()) ||
2213  !math::IsPowerOfTwo(image.GetHeight())) {
2218  if ((sampler->GetWrapS() == Sampler::kClampToEdge ||
2219  sampler->GetWrapT() == Sampler::kClampToEdge) &&
2220  (sampler->GetMinFilter() >= Sampler::kNearestMipmapNearest)) {
2221  LOG(ERROR)
2222  << "***ION: Non-power-of-two textures using wrap mode "
2223  << "CLAMP_TO_EDGE must use either NEAREST or LINEAR minification "
2224  << "filter modes, use Texture::SetMinFilter(Sampler::kNearest) "
2225  << "or Texture::SetMinFilter(Sampler::kLinear) to fix this";
2226  return false;
2227  }
2228  }
2229  }
2230  return true;
2231 }
2232 
2233 void Renderer::TextureResource::UploadImage(const Image& image, GLenum target,
2234  GLint level, int samples,
2235  bool fixed_sample_locations,
2236  bool is_full_image,
2237  const Point3ui& offset,
2238  GraphicsManager* gm) {
2239  const Image::PixelFormat pf =
2240  GetCompatiblePixelFormat(Image::GetPixelFormat(image.GetFormat()), gm);
2241  const int component_count =
2242  Image::GetNumComponentsForFormat(image.GetFormat());
2243  if (last_uploaded_components_ &&
2244  component_count < last_uploaded_components_) {
2245  LOG(WARNING)
2246  << "While uploading image data for texture \""
2247  << GetTexture<TextureBase>().GetLabel()
2248  << "\", the number of components for this upload is " << component_count
2249  << " but was " << last_uploaded_components_
2250  << " the last time data was uploaded. This is likely not what you want "
2251  "as GL implementations are not guaranteed to provide particular "
2252  "values for the unset components.";
2253  }
2254  last_uploaded_components_ = component_count;
2255 
2256  const DataContainerPtr& container = image.GetData();
2257  const void* data = container.Get() ? container->GetData() : nullptr;
2258  gm->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
2259 
2260  const bool multisample = (samples > 0) &&
2261  gm->IsFunctionGroupAvailable(GraphicsManager::kTextureMultisample);
2262 
2263  if (image.GetType() == Image::kEgl ||
2264  image.GetType() == Image::kExternalEgl) {
2267  if (data && gm->IsFunctionGroupAvailable(GraphicsManager::kEglImage)) {
2268  DCHECK(gl_target_ == GL_TEXTURE_EXTERNAL_OES ||
2269  gl_target_ == GL_TEXTURE_2D);
2270  gm->EGLImageTargetTexture2DOES(gl_target_, const_cast<void*>(data));
2271  }
2272  } else if (image.GetWidth() > 0U && image.GetHeight() > 0U &&
2273  image.GetDepth() > 0U) {
2277  if (image.IsCompressed() && data) {
2278  if (image.GetDimensions() == Image::k2d) {
2279  const size_t data_size = Image::ComputeDataSize(
2280  image.GetFormat(), image.GetWidth(), image.GetHeight());
2281  if (is_full_image) {
2282  gm->CompressedTexImage2D(target, level, pf.internal_format,
2283  image.GetWidth(), image.GetHeight(), 0,
2284  static_cast<GLsizei>(data_size), data);
2285  } else {
2286  gm->CompressedTexSubImage2D(target, level, offset[0], offset[1],
2287  image.GetWidth(), image.GetHeight(),
2288  pf.internal_format,
2289  static_cast<GLsizei>(data_size), data);
2290  }
2291  } else if (image.GetDimensions() == Image::k3d) {
2292  const size_t data_size =
2293  Image::ComputeDataSize(image.GetFormat(), image.GetWidth(),
2294  image.GetHeight(), image.GetDepth());
2295  if (gm->IsFunctionGroupAvailable(GraphicsManager::kTexture3d)) {
2296  if (is_full_image) {
2297  gm->CompressedTexImage3D(target, level, pf.internal_format,
2298  image.GetWidth(), image.GetHeight(),
2299  image.GetDepth(), 0,
2300  static_cast<GLsizei>(data_size), data);
2301  } else {
2302  gm->CompressedTexSubImage3D(
2303  target, level, offset[0], offset[1], offset[2],
2304  image.GetWidth(), image.GetHeight(), image.GetDepth(),
2305  pf.internal_format, static_cast<GLsizei>(data_size), data);
2306  }
2307  } else {
2308  LOG(ERROR) << "***ION: 3D texturing is not supported by the local "
2309  << "OpenGL implementation, but Texture \""
2310  << GetTexture<TextureBase>().GetLabel()
2311  << "\" contains a 3D Image.";
2312  }
2313  }
2314  } else {
2315  if (image.GetDimensions() == Image::k2d) {
2316  if (is_full_image) {
2317  if (multisample) {
2318  gm->TexImage2DMultisample(target, samples, pf.internal_format,
2319  image.GetWidth(), image.GetHeight(),
2320  fixed_sample_locations);
2321  } else {
2322  gm->TexImage2D(target, level, pf.internal_format, image.GetWidth(),
2323  image.GetHeight(), 0, pf.format, pf.type, data);
2324  }
2325  } else {
2326  gm->TexSubImage2D(target, level, offset[0], offset[1],
2327  image.GetWidth(), image.GetHeight(), pf.format,
2328  pf.type, data);
2329  }
2330  } else if (image.GetDimensions() == Image::k3d) {
2331  if (gm->IsFunctionGroupAvailable(GraphicsManager::kTexture3d)) {
2332  if (is_full_image) {
2333  if (multisample) {
2334  gm->TexImage3DMultisample(
2335  target, samples, pf.internal_format, image.GetWidth(),
2336  image.GetHeight(), image.GetDepth(), fixed_sample_locations);
2337  } else {
2338  gm->TexImage3D(target, level, pf.internal_format,
2339  image.GetWidth(), image.GetHeight(),
2340  image.GetDepth(), 0, pf.format, pf.type, data);
2341  }
2342  } else {
2343  gm->TexSubImage3D(target, level, offset[0], offset[1], offset[2],
2344  image.GetWidth(), image.GetHeight(),
2345  image.GetDepth(), pf.format, pf.type, data);
2346  }
2347  } else {
2348  LOG(ERROR) << "***ION: 3D texturing is not supported by the local "
2349  << "OpenGL implementation, but Texture \""
2350  << GetTexture<TextureBase>().GetLabel()
2351  << "\" contains a 3D Image.";
2352  }
2353  }
2354  }
2355  }
2356  if (data)
2357  container->WipeData();
2358 }
2359 
2360 void Renderer::TextureResource::UpdateMipmapGeneration(const Sampler& sampler,
2361  bool image_has_changed,
2362  GraphicsManager* gm) {
2363  const bool is_auto_mipmapping_enabled =
2364  sampler.IsAutogenerateMipmapsEnabled();
2365  const bool auto_mipmapping_changed =
2366  auto_mipmapping_enabled_ != is_auto_mipmapping_enabled;
2367  if (auto_mipmapping_changed)
2368  auto_mipmapping_enabled_ = is_auto_mipmapping_enabled;
2369  if ((image_has_changed || auto_mipmapping_changed ||
2370  TestModifiedBit(TextureBase::kContentsImplicitlyChanged)) &&
2371  auto_mipmapping_enabled_)
2372  gm->GenerateMipmap(gl_target_);
2373 }
2374 
2375 void Renderer::TextureResource::UpdateState(const TextureBase& texture,
2376  ResourceBinder* rb, GLuint unit) {
2378  GraphicsManager* gm = GetGraphicsManager();
2379  DCHECK(gm);
2380 
2383  const bool multisample = (texture.GetMultisampleSamples() > 0) &&
2384  gm->IsFunctionGroupAvailable(GraphicsManager::kTextureMultisample);
2385  const bool multisample_changed = SetMultisampleEnabledByRenderer(multisample);
2386 
2387  if (!id_ || AnyModifiedBitsSet()) {
2388  ScopedResourceLabel label(this, rb);
2389  if (!id_)
2390  gm->GenTextures(1, &id_);
2391  if (id_) {
2392  UpdateTextureTarget(gm, multisample);
2393 
2396  if (TestModifiedBit(ResourceHolder::kResourceChanged))
2397  rb->ClearTextureBinding(id_, unit);
2399  rb->ActivateUnit(unit);
2400  rb->BindTextureToUnit(this, unit);
2401 
2403  if (multisample_changed ||
2404  TestModifiedBit(TextureBase::kImmutableImageChanged)) {
2405  if (Image* image = texture.GetImmutableImage().Get())
2406  CreateImmutableTexture(*image, multisample,
2407  texture.GetMultisampleSamples(),
2408  texture.IsMultisampleFixedSampleLocations(),
2409  texture.GetImmutableLevels(), gm);
2410  }
2411  if (texture.GetTextureType() == TextureBase::kCubeMapTexture)
2412  UpdateCubeMapImageState(gm);
2413  else
2414  UpdateTextureImageState(gm, multisample, multisample_changed);
2415  UpdateMemoryUsage(texture.GetTextureType());
2416  if (TestModifiedBit(TextureBase::kSamplerChanged) &&
2417  !GetGraphicsManager()->IsFunctionGroupAvailable(
2419  if (Sampler* sampler = GetTexture<TextureBase>().GetSampler().Get())
2420  UpdateSamplerState(*sampler, gm);
2421  UpdateTextureState(texture, gm);
2422  SetObjectLabel(gm, GL_TEXTURE, id_, texture.GetLabel());
2423  ResetModifiedBits();
2424  } else {
2425  LOG(ERROR) << "***ION: Unable to create texture object";
2426  }
2427  }
2428 }
2429 
2430 void Renderer::TextureResource::UpdateSamplerState(const Sampler& sampler,
2431  GraphicsManager* gm) {
2433  if (max_anisotropy_ != sampler.GetMaxAnisotropy() &&
2434  gm->IsExtensionSupported("texture_filter_anisotropic")) {
2435  max_anisotropy_ = sampler.GetMaxAnisotropy();
2436  const float aniso = std::min(
2437  max_anisotropy_, GetGraphicsManager()->GetCapabilityValue<float>(
2439  gm->TexParameterf(gl_target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
2440  }
2441  if (min_filter_ != sampler.GetMinFilter()) {
2442  min_filter_ = sampler.GetMinFilter();
2443  gm->TexParameteri(gl_target_, GL_TEXTURE_MIN_FILTER,
2444  base::EnumHelper::GetConstant(min_filter_));
2445  }
2446  if (mag_filter_ != sampler.GetMagFilter()) {
2447  mag_filter_ = sampler.GetMagFilter();
2448  gm->TexParameteri(gl_target_, GL_TEXTURE_MAG_FILTER,
2449  base::EnumHelper::GetConstant(mag_filter_));
2450  }
2451  if (wrap_s_ != sampler.GetWrapS()) {
2452  wrap_s_ = sampler.GetWrapS();
2453  gm->TexParameteri(gl_target_, GL_TEXTURE_WRAP_S,
2455  }
2456  if (wrap_t_ != sampler.GetWrapT()) {
2457  wrap_t_ = sampler.GetWrapT();
2458  gm->TexParameteri(gl_target_, GL_TEXTURE_WRAP_T,
2460  }
2461 
2462  if (gm->GetGlVersion() > 20) {
2464  if (compare_function_ != sampler.GetCompareFunction()) {
2465  compare_function_ = sampler.GetCompareFunction();
2466  gm->TexParameteri(gl_target_, GL_TEXTURE_COMPARE_FUNC,
2467  base::EnumHelper::GetConstant(compare_function_));
2468  }
2469  if (compare_mode_ != sampler.GetCompareMode()) {
2470  compare_mode_ = sampler.GetCompareMode();
2471  gm->TexParameteri(gl_target_, GL_TEXTURE_COMPARE_MODE,
2472  compare_mode_ == Sampler::kCompareToTexture
2473  ? GL_COMPARE_REF_TO_TEXTURE
2474  : GL_NONE);
2475  }
2476  if (max_lod_ != sampler.GetMaxLod()) {
2477  max_lod_ = sampler.GetMaxLod();
2478  gm->TexParameterf(gl_target_, GL_TEXTURE_MAX_LOD, max_lod_);
2479  }
2480  if (min_lod_ != sampler.GetMinLod()) {
2481  min_lod_ = sampler.GetMinLod();
2482  gm->TexParameterf(gl_target_, GL_TEXTURE_MIN_LOD, min_lod_);
2483  }
2484  if (wrap_r_ != sampler.GetWrapR()) {
2485  wrap_r_ = sampler.GetWrapR();
2486  gm->TexParameteri(gl_target_, GL_TEXTURE_WRAP_R,
2488  }
2489  }
2490 }
2491 
2492 void Renderer::TextureResource::UpdateTextureState(const TextureBase& texture,
2493  GraphicsManager* gm) {
2494  if (gm->GetGlVersion() > 20) {
2495  if (TestModifiedBit(TextureBase::kBaseLevelChanged))
2496  gm->TexParameteri(gl_target_, GL_TEXTURE_BASE_LEVEL,
2497  texture.GetBaseLevel());
2498  if (TestModifiedBit(TextureBase::kMaxLevelChanged))
2499  gm->TexParameteri(gl_target_, GL_TEXTURE_MAX_LEVEL,
2500  texture.GetMaxLevel());
2501  if ((gm->GetGlApiStandard() == GraphicsManager::kEs &&
2502  gm->GetGlVersion() >= 30) ||
2503  (gm->GetGlApiStandard() == GraphicsManager::kDesktop &&
2504  gm->GetGlVersion() >= 33)) {
2505  if (TestModifiedBit(TextureBase::kSwizzleRedChanged))
2506  gm->TexParameteri(
2507  gl_target_, GL_TEXTURE_SWIZZLE_R,
2508  base::EnumHelper::GetConstant(texture.GetSwizzleRed()));
2509  if (TestModifiedBit(TextureBase::kSwizzleGreenChanged))
2510  gm->TexParameteri(
2511  gl_target_, GL_TEXTURE_SWIZZLE_G,
2512  base::EnumHelper::GetConstant(texture.GetSwizzleGreen()));
2513  if (TestModifiedBit(TextureBase::kSwizzleBlueChanged))
2514  gm->TexParameteri(
2515  gl_target_, GL_TEXTURE_SWIZZLE_B,
2516  base::EnumHelper::GetConstant(texture.GetSwizzleBlue()));
2517  if (TestModifiedBit(TextureBase::kSwizzleAlphaChanged))
2518  gm->TexParameteri(
2519  gl_target_, GL_TEXTURE_SWIZZLE_A,
2520  base::EnumHelper::GetConstant(texture.GetSwizzleAlpha()));
2521  }
2522  }
2523 }
2524 
2525 void Renderer::TextureResource::Unbind(ResourceBinder* rb) {
2528  if (rb) {
2529  const GLuint count = static_cast<GLuint>(rb->GetImageUnitCount());
2530  for (GLuint i = 0U; i < count; ++i)
2531  rb->ClearTextureBinding(id_, i);
2532  }
2533 }
2534 
2535 void Renderer::TextureResource::Release(bool can_make_gl_calls) {
2536  BaseResourceType::Release(can_make_gl_calls);
2537  if (id_) {
2539  base::ReadLock read_lock(GetResourceBinderLock());
2540  base::ReadGuard read_guard(&read_lock);
2541  ResourceBinderMap& binders = GetResourceBinderMap();
2542  for (ResourceBinderMap::iterator it = binders.begin();
2543  it != binders.end();
2544  ++it) {
2545  Unbind(it->second.get());
2546  it->second->ClearAssignedImageUnit(this);
2547  }
2548 
2549  if (resource_owns_gl_id_ && can_make_gl_calls)
2550  GetGraphicsManager()->DeleteTextures(1, &id_);
2551  SetUsedGpuMemory(0U);
2552  id_ = 0;
2553  }
2554 }
2555 
2556 bool Renderer::TextureResource::IsComplete() const {
2558  const TextureBase& base = GetTexture<TextureBase>();
2559  if (!base.GetSampler().Get()) {
2560  LOG(WARNING) << "***ION: Texture \""
2561  << GetTexture<TextureBase>().GetLabel()
2562  << "\" has no Sampler! It will likely appear black.";
2563  return false;
2564  }
2565 
2567  if (base.GetImmutableImage().Get())
2568  return true;
2569 
2570  if (base.GetTextureType() == TextureBase::kCubeMapTexture) {
2571  const CubeMapTexture& texture = GetTexture<CubeMapTexture>();
2574  bool valid = true;
2575  for (int i = 0; i < 6; ++i) {
2576  const CubeMapTexture::CubeFace face =
2577  static_cast<CubeMapTexture::CubeFace>(i);
2578  if (!texture.HasImage(face, 0U)) {
2579  LOG(WARNING) << "***ION: Cubemap texture face "
2581  << " has no level 0 mipmap.";
2582  return false;
2583  }
2584  }
2585  return valid;
2586  } else {
2587  const Texture& texture = GetTexture<Texture>();
2588  if (!texture.HasImage(0U)) {
2589  LOG(WARNING) << "***ION: Texture \"" << texture.GetLabel()
2590  << "\" has no level 0 mipmap";
2591  return false;
2592  } else {
2593  return true;
2594  }
2595  }
2596 }
2597 
2598 bool Renderer::TextureResource::UpdateMipmap0Image(
2599  const Image& image, const TextureBase& texture, const size_t mipmap_count,
2600  GLenum target, int mipmap_changed_bit, GraphicsManager* gm,
2601  size_t* required_levels, bool multisample_changed) {
2602  const uint32 width = image.GetWidth();
2603  const uint32 height = image.GetHeight();
2604 
2605  const bool mipmap_changed = TestModifiedBit(mipmap_changed_bit);
2606 
2608  if ((mipmap_changed || multisample_changed) && CheckImage(image, texture)) {
2609  const int samples = texture.GetMultisampleSamples();
2610  const bool fixed_sample_locations =
2611  texture.IsMultisampleFixedSampleLocations();
2612  UploadImage(image, target, 0, samples, fixed_sample_locations, true,
2613  Point3ui(), gm);
2614  }
2615 
2618  *required_levels = std::max(math::Log2(width), math::Log2(height)) + 1;
2622  return mipmap_count < *required_levels && mipmap_count > 1U;
2623 }
2624 
2625 bool Renderer::TextureResource::UpdateImage(const Image& image0,
2626  const Image& mipmap,
2627  const TextureBase& texture,
2628  GLenum target,
2629  int level,
2630  GraphicsManager* gm) {
2632  const Image::Format& format = image0.GetFormat();
2633  uint32 expected_width = 0;
2634  uint32 expected_height = 0;
2635  if (mipmap.GetFormat() != format) {
2636  LOG(ERROR) << "***ION: Mipmap level " << level << " has different"
2637  << " format [" << mipmap.GetFormat() << "] from level 0's ["
2638  << format << "], ignoring";
2639  } else if (Texture::ExpectedDimensionsForMipmap(mipmap.GetWidth(),
2640  mipmap.GetHeight(),
2641  level,
2642  image0.GetWidth(),
2643  image0.GetHeight(),
2644  &expected_width,
2645  &expected_height)) {
2647  UploadImage(mipmap, target, level, 0, false, true, Point3ui(), gm);
2648  return true;
2649  }
2650  return false;
2651 }
2652 
2653 void Renderer::TextureResource::UpdateSubImages(
2654  const base::AllocVector<Texture::SubImage>& images, GLenum target,
2655  GraphicsManager* gm) {
2656  const size_t count = images.size();
2657  for (size_t i = 0; i < count; ++i) {
2658  const Image& image = *images[i].image.Get();
2660  UploadImage(image, target, static_cast<GLint>(images[i].level), 0, false,
2661  false, images[i].offset, gm);
2662  }
2663 }
2664 
2665 void Renderer::TextureResource::UpdateMemoryUsage(
2666  TextureBase::TextureType type) {
2667  size_t data_size = 0U;
2668  if (type == TextureBase::kTexture) {
2669  const Texture& tex = GetTexture<Texture>();
2670  if (tex.HasImage(0)) {
2671  const Image& image = *tex.GetImage(0);
2672  const Sampler* samp = tex.GetSampler().Get();
2673  const bool auto_mipmap = samp && samp->IsAutogenerateMipmapsEnabled();
2674  if (tex.GetImageCount() > 1 || auto_mipmap) {
2675  data_size = Image::ComputeDataSize(image.GetFormat(), image.GetWidth(),
2676  image.GetHeight());
2679  data_size = (data_size * 4) / 3;
2680  } else {
2681  data_size = Image::ComputeDataSize(image.GetFormat(), image.GetWidth(),
2682  image.GetHeight());
2683  }
2684  }
2685  } else { // kCubeMapTexture.
2686  const CubeMapTexture& tex = GetTexture<CubeMapTexture>();
2687  if (tex.HasImage(CubeMapTexture::kNegativeX, 0)) {
2688  const Image& image = *tex.GetImage(CubeMapTexture::kNegativeX, 0);
2689  const Sampler* samp = tex.GetSampler().Get();
2690  const bool auto_mipmap = samp && samp->IsAutogenerateMipmapsEnabled();
2691  if (tex.GetImageCount(CubeMapTexture::kNegativeX) > 1 || auto_mipmap) {
2692  data_size = Image::ComputeDataSize(image.GetFormat(), image.GetWidth(),
2693  image.GetHeight());
2695  data_size = data_size * 8;
2696  } else {
2697  data_size = Image::ComputeDataSize(image.GetFormat(), image.GetWidth(),
2698  image.GetHeight());
2699  data_size *= 6;
2700  }
2701  }
2702  }
2703 
2704  SetUsedGpuMemory(data_size);
2705 }
2706 
2707 void Renderer::TextureResource::UpdateTextureImageState(
2708  GraphicsManager* gm, const bool multisample,
2709  const bool multisample_changed) {
2710  const Texture& texture = GetTexture<Texture>();
2711  const bool mipmap_changed = TestModifiedBitRange(
2712  Texture::kMipmapChanged, Texture::kMipmapChanged + kMipmapSlotCount);
2713 
2714  if ((mipmap_changed || multisample_changed) && texture.HasImage(0)) {
2715  if (multisample) {
2716  const Image& image0 = *texture.GetImage(0);
2717  size_t required_levels = 0U;
2718  UpdateMipmap0Image(image0, texture, texture.GetImageCount(), gl_target_,
2719  Texture::kMipmapChanged, gm, &required_levels,
2720  multisample_changed);
2721  } else {
2724  const Image& image0 = *texture.GetImage(0);
2725  size_t required_levels = 0U;
2726  const bool generate_mipmaps = UpdateMipmap0Image(
2727  image0, texture, texture.GetImageCount(), gl_target_,
2728  Texture::kMipmapChanged, gm, &required_levels, multisample_changed);
2729  if (generate_mipmaps || multisample_changed)
2730  gm->GenerateMipmap(gl_target_);
2731 
2732  for (size_t i = 1; i < required_levels; ++i) {
2733  if (texture.HasImage(i) &&
2734  CheckImage(*texture.GetImage(i), texture) &&
2735  (generate_mipmaps || multisample_changed ||
2736  TestModifiedBit(static_cast<Texture::Changes>(
2737  Texture::kMipmapChanged + i)))) {
2738  UpdateImage(image0, *texture.GetImage(i), texture, gl_target_,
2739  static_cast<int>(i), gm);
2740  }
2741  }
2742  }
2743  }
2744 
2745  if (!multisample) {
2746  if (multisample_changed || TestModifiedBit(Texture::kSubImageChanged)) {
2747  UpdateSubImages(texture.GetSubImages(), gl_target_, gm);
2748  texture.ClearSubImages();
2749  }
2750 
2752  if (Sampler* sampler = texture.GetSampler().Get()) {
2753  if (texture.HasImage(0U))
2754  UpdateMipmapGeneration(*sampler, multisample_changed ||
2755  TestModifiedBit(Texture::kMipmapChanged), gm);
2756  }
2757  }
2758 }
2759 
2760 void Renderer::TextureResource::CreateImmutableTexture(
2761  const Image& image, const bool multisample, const size_t samples,
2762  const bool fixed_sample_locations, size_t levels, GraphicsManager* gm) {
2763  Image::PixelFormat pf =
2764  GetCompatiblePixelFormat(Image::GetPixelFormat(image.GetFormat()), gm);
2765  if (image.GetDimensions() == Image::k2d) {
2766  if (multisample) {
2767  gm->TexStorage2DMultisample(gl_target_, static_cast<GLsizei>(samples),
2768  pf.internal_format, image.GetWidth(),
2769  image.GetHeight(),
2770  static_cast<GLboolean>(
2771  fixed_sample_locations));
2772 
2773  } else {
2774  gm->TexStorage2D(gl_target_, static_cast<GLsizei>(levels),
2775  pf.internal_format, image.GetWidth(),
2776  image.GetHeight());
2777  }
2778  } else if (image.GetDimensions() == Image::k3d) {
2779  if (multisample) {
2780  gm->TexStorage3DMultisample(gl_target_, static_cast<GLsizei>(samples),
2781  pf.internal_format, image.GetWidth(),
2782  image.GetHeight(), image.GetDepth(),
2783  static_cast<GLboolean>(
2784  fixed_sample_locations));
2785  } else {
2786  gm->TexStorage3D(gl_target_, static_cast<GLsizei>(levels),
2787  pf.internal_format, image.GetWidth(), image.GetHeight(),
2788  image.GetDepth());
2789  }
2790  }
2791 }
2792 
2793 void Renderer::TextureResource::UpdateCubeMapImageState(GraphicsManager* gm) {
2796  const CubeMapTexture& texture = GetTexture<CubeMapTexture>();
2797  static const int kSlotCount = static_cast<int>(kMipmapSlotCount);
2798 
2800  bool images_have_changed = false;
2801  bool need_to_generate_mipmaps = false;
2802  size_t required_levels[6];
2803  for (int i = 0; i < 6; ++i) {
2804  const CubeMapTexture::CubeFace face =
2805  static_cast<CubeMapTexture::CubeFace>(i);
2806  const int base_mipmap_bit =
2807  CubeMapTexture::kNegativeXMipmapChanged + i * kSlotCount;
2808  required_levels[i] = 0U;
2809  if (TestModifiedBitRange(base_mipmap_bit, base_mipmap_bit + kSlotCount) &&
2810  texture.HasImage(face, 0U)) {
2811  const Image& image = *texture.GetImage(face, 0U);
2813  const GLenum target = image.GetDimensions() == Image::k3d
2814  ? gl_target_
2816  if (image.GetWidth() == image.GetHeight()) {
2817  if (UpdateMipmap0Image(image, texture, texture.GetImageCount(face),
2818  target, base_mipmap_bit, gm, &required_levels[i],
2819  false)) {
2820  need_to_generate_mipmaps = true;
2821  images_have_changed = true;
2822  }
2823  } else {
2824  LOG(ERROR) << "Level 0 mimpap for face "
2825  << base::EnumHelper::GetString(face) << " of cubemap \""
2826  << texture.GetLabel()
2827  << "\" does not have square dimensions. OpenGL requires "
2828  << "cubemap faces to have square dimensions";
2829  }
2830  }
2831  }
2833  if (need_to_generate_mipmaps)
2834  gm->GenerateMipmap(gl_target_);
2835 
2837  for (int j = 0; j < 6; ++j) {
2838  const CubeMapTexture::CubeFace face =
2839  static_cast<CubeMapTexture::CubeFace>(j);
2840  const int base_subimage_bit = CubeMapTexture::kNegativeXSubImageChanged;
2841  const int base_mipmap_bit =
2842  CubeMapTexture::kNegativeXMipmapChanged + j * kSlotCount;
2843  if (TestModifiedBitRange(base_mipmap_bit, base_mipmap_bit + kSlotCount) &&
2844  texture.HasImage(face, 0U)) {
2845  const Image& image0 = *texture.GetImage(face, 0U);
2846  const GLenum target = image0.GetDimensions() == Image::k3d
2847  ? gl_target_
2849  for (size_t i = 1; i < required_levels[j]; ++i) {
2850  if (texture.HasImage(face, i) &&
2851  CheckImage(*texture.GetImage(face, i), texture) &&
2852  (need_to_generate_mipmaps ||
2853  TestModifiedBit(static_cast<int>(base_mipmap_bit + i)))) {
2854  if (!UpdateImage(image0, *texture.GetImage(face, i), texture, target,
2855  static_cast<int>(i), gm)) {
2857  images_have_changed = false;
2858  break;
2859  }
2860  }
2861  }
2862  }
2863 
2864  if (TestModifiedBit(base_subimage_bit + j)) {
2865  const GLenum target = base::EnumHelper::GetConstant(face);
2866  UpdateSubImages(texture.GetSubImages(face), target, gm);
2867  texture.ClearSubImages(face);
2868  }
2869  }
2870 
2872  if (Sampler* sampler = texture.GetSampler().Get())
2873  UpdateMipmapGeneration(*sampler, images_have_changed, gm);
2874 }
2875 
2877 
2882 
2883 
2884 class Renderer::ShaderResource : public Resource<Shader::kNumChanges> {
2885  public:
2886  ShaderResource(ResourceBinder* rb, ResourceManager* rm, const Shader& shader,
2887  ResourceKey key, GLuint id)
2888  : Renderer::Resource<Shader::kNumChanges>(rm, shader, key, id),
2889  shader_type_(GL_INVALID_ENUM) {}
2890 
2891  ~ShaderResource() override {
2892  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
2893  }
2894 
2896  virtual bool UpdateShader(ResourceBinder* rb);
2897  void Release(bool can_make_gl_calls) override;
2898  ResourceType GetType() const override { return kShader; }
2899 
2901  void SetShaderType(GLenum type) { shader_type_ = type; }
2902 
2903  const Shader& GetShader() const {
2904  return static_cast<const Shader&>(*GetHolder());
2905  }
2906 
2907  void Bind(ResourceBinder* rb) {}
2908  void Unbind(ResourceBinder* rb) override {}
2909  void Update(ResourceBinder* rb) override {}
2910 
2911  private:
2913  GLenum shader_type_;
2914 };
2915 
2916 bool Renderer::ShaderResource::UpdateShader(ResourceBinder* rb) {
2917  if (AnyModifiedBitsSet()) {
2918  ScopedResourceLabel label(this, rb);
2920  Update(rb);
2921 
2922  const Shader& shader = GetShader();
2923  const std::string& id_string = shader.GetLabel();
2924  GraphicsManager* gm = GetGraphicsManager();
2925 
2926  std::string info_log = shader.GetInfoLog();
2927  bool need_to_update_label = TestModifiedBit(ResourceHolder::kLabelChanged);
2928  if (TestModifiedBit(Shader::kSourceChanged)) {
2929  GLuint id = CompileShader(id_string, shader_type_, shader.GetSource(),
2930  &info_log, gm);
2932  if (id) {
2933  id_ = id;
2934  need_to_update_label = true;
2935  }
2936  }
2937 
2938  if (need_to_update_label)
2939  SetObjectLabel(gm, GL_SHADER_OBJECT, id_, id_string);
2940 
2942  shader.SetInfoLog(info_log);
2943  ResetModifiedBits();
2944 
2945  return true;
2946  } else {
2947  return false;
2948  }
2949 }
2950 
2951 void Renderer::ShaderResource::Release(bool can_make_gl_calls) {
2952  BaseResourceType::Release(can_make_gl_calls);
2953  GraphicsManager* gm = GetGraphicsManager();
2954  if (id_) {
2955  if (resource_owns_gl_id_ && can_make_gl_calls)
2956  gm->DeleteShader(id_);
2957  id_ = 0;
2958  }
2959 }
2960 
2962 
2970 
2971 
2972 class Renderer::ShaderInputRegistryResource
2973  : public Resource<ShaderInputRegistry::kNumChanges> {
2974  public:
2975  ShaderInputRegistryResource(ResourceBinder* rb, ResourceManager* rm,
2976  const ShaderInputRegistry& reg,
2977  ResourceKey key, GLuint id)
2978  : Renderer::Resource<ShaderInputRegistry::kNumChanges>(rm, reg, key, id),
2979  uniform_stacks_(reg.GetAllocator()) {
2980  uniform_stacks_.reserve(reg.GetSpecs<Uniform>().size());
2981  }
2982 
2983  ~ShaderInputRegistryResource() override {}
2984  ResourceType GetType() const override { return kShaderInputRegistry; }
2985 
2986  void Unbind(ResourceBinder* rb) override {
2990  for (auto& stack : uniform_stacks_)
2991  stack->Clear();
2992  }
2993 
2995  const Uniform& GetUniform(size_t index) const {
2996  DCHECK_LT(index, uniform_stacks_.size());
2997  return *uniform_stacks_[index]->GetTop();
2998  }
2999 
3001  void SetInitialValue(const Uniform& u) {
3002  DCHECK_EQ(&u.GetRegistry(), &GetRegistry());
3003  DCHECK_LT(u.GetIndexInRegistry(), uniform_stacks_.size());
3004  UniformStack& uis = *uniform_stacks_[u.GetIndexInRegistry()];
3005  uis.SetBottom(u);
3006  }
3007 
3009  void PushUniform(const Uniform& u) {
3010  DCHECK_EQ(&u.GetRegistry(), &GetRegistry());
3011  DCHECK_LT(u.GetIndexInRegistry(), uniform_stacks_.size());
3012  DCHECK(u.IsValid());
3013  UniformStack& uis = *uniform_stacks_[u.GetIndexInRegistry()];
3014  const ShaderInputRegistry::CombineFunction<Uniform>::Type& combine_func =
3015  ShaderInputRegistry::GetSpec(u)->combine_function;
3016  const ShaderInputRegistry::GenerateFunction<Uniform>::Type& generate_func =
3017  ShaderInputRegistry::GetSpec(u)->generate_function;
3018  const Uniform& top = *uis.GetTop();
3020  Uniform* temp = uis.GetTopTempUniform();
3021  if (combine_func && top.IsValid()) {
3023  *temp = combine_func(top, u);
3024  uis.PushTempUniform(temp);
3025  } else if (Uniform::GetMerged(top, u, temp)) {
3027  uis.PushTempUniform(temp);
3028  } else {
3030  uis.Push(&u);
3031  }
3032  if (generate_func) {
3034  std::vector<Uniform> generated = generate_func(*uis.GetTop());
3035  const size_t count = generated.size();
3036  for (size_t i = 0; i < count; ++i) {
3037  const Uniform& gen = generated[i];
3038  if (gen.IsValid()) {
3040  DCHECK_EQ(&u.GetRegistry(), &GetRegistry());
3041  DCHECK_LT(gen.GetIndexInRegistry(), uniform_stacks_.size());
3042  UniformStack& uis = *uniform_stacks_[gen.GetIndexInRegistry()];
3043  Uniform* temp = uis.GetTopTempUniform();
3044  *temp = gen;
3045  uis.PushTempUniform(temp);
3046  }
3047  }
3048  }
3049  }
3050 
3052  void PopUniform(const Uniform& u) {
3053  DCHECK_EQ(&u.GetRegistry(), &GetRegistry());
3054  DCHECK_LT(u.GetIndexInRegistry(), uniform_stacks_.size());
3055  uniform_stacks_[u.GetIndexInRegistry()]->Pop();
3056  }
3057 
3058  void Update(ResourceBinder* rb) override {
3059  if (AnyModifiedBitsSet()) {
3062  const size_t size = GetRegistry().GetSpecs<Uniform>().size();
3063  for (size_t i = uniform_stacks_.size(); i < size; ++i) {
3064  uniform_stacks_.push_back(std::unique_ptr<UniformStack>(
3065  new(uniform_stacks_.get_allocator().GetAllocator()) UniformStack));
3066  }
3067  ResetModifiedBits();
3068  }
3069  }
3070 
3071  private:
3076  class UniformStack : public Allocatable {
3077  public:
3078  UniformStack()
3079  : uniform_stack_(
3080  base::AllocationManager::GetDefaultAllocatorForLifetime(
3081  base::kShortTerm)),
3082  temp_stack_(base::AllocationManager::GetDefaultAllocatorForLifetime(
3083  base::kShortTerm)),
3084  pristine_(true) {
3085  Init();
3086  }
3087  Uniform* GetTopTempUniform() {
3088  DCHECK_GT(temp_stack_.size(), 1U);
3089  return &temp_stack_.back();
3090  }
3091  const Uniform* GetTop() const {
3092  DCHECK(!uniform_stack_.empty());
3093  return uniform_stack_.back();
3094  }
3095  void Pop() {
3096  DCHECK(!temp_stack_.empty());
3097  DCHECK(!uniform_stack_.empty());
3098  if (IsTopATempUniform())
3099  temp_stack_.pop_back();
3100  uniform_stack_.pop_back();
3101  pristine_ = false;
3102  }
3103  void PushTempUniform(Uniform* temp) {
3104  DCHECK(!uniform_stack_.empty());
3105  DCHECK(!temp_stack_.empty());
3106  DCHECK(temp == GetTopTempUniform());
3108  temp_stack_.push_back(Uniform());
3109  uniform_stack_.push_back(temp);
3110  pristine_ = false;
3111  }
3112  void Push(const Uniform* uniform) {
3113  DCHECK(!uniform_stack_.empty());
3114  DCHECK(uniform != GetTopTempUniform());
3115  uniform_stack_.push_back(uniform);
3116  pristine_ = false;
3117  }
3118  void SetBottom(const Uniform& uniform) {
3119  DCHECK(!uniform_stack_.empty());
3120  DCHECK(!temp_stack_.empty());
3121  temp_stack_[0] = uniform;
3122  uniform_stack_[0] = &temp_stack_[0];
3123  pristine_ = false;
3124  }
3125  void Clear() {
3126  if (!pristine_) {
3127  uniform_stack_.clear();
3128  temp_stack_.clear();
3129  Init();
3130  pristine_ = true;
3131  }
3132  }
3133  size_t Size() const { return uniform_stack_.size(); }
3134 
3135  private:
3136  void Init() {
3138  temp_stack_.push_back(Uniform());
3139  uniform_stack_.push_back(&temp_stack_.back());
3141  temp_stack_.push_back(Uniform());
3142  }
3143  bool IsTopATempUniform() {
3146  const size_t size = temp_stack_.size();
3147  return (size > 1U &&
3148  uniform_stack_.back() == &temp_stack_[size - 2]);
3149  }
3150  base::AllocVector<const Uniform*> uniform_stack_;
3155  base::AllocDeque<Uniform> temp_stack_;
3157  bool pristine_;
3158  };
3159 
3160  const ShaderInputRegistry& GetRegistry() const {
3161  return static_cast<const ShaderInputRegistry&>(*GetHolder());
3162  }
3163 
3164  base::AllocVector<std::unique_ptr<UniformStack>> uniform_stacks_;
3165 };
3166 
3168 
3173 
3174 
3175 class Renderer::ShaderProgramResource
3176  : public Resource<ShaderProgram::kNumChanges> {
3177  public:
3178  ShaderProgramResource(ResourceBinder* rb, ResourceManager* rm,
3179  const ShaderProgram& shader_program, ResourceKey key,
3180  GLuint id)
3181  : Renderer::Resource<ShaderProgram::kNumChanges>(rm, shader_program, key,
3182  id),
3183  attribute_index_map_(shader_program.GetAllocator()),
3184  uniforms_(shader_program.GetAllocator()),
3185  vertex_resource_(nullptr),
3186  fragment_resource_(nullptr) {}
3187 
3188  GLint GetAttributeIndex(
3189  const ShaderInputRegistry::AttributeSpec* spec) const {
3190  AttributeIndexMap::const_iterator it = attribute_index_map_.find(spec);
3191  return it == attribute_index_map_.end() ? -1 : it->second;
3192  }
3193 
3194  ~ShaderProgramResource() override {
3195  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
3196  }
3197 
3198  void Release(bool can_make_gl_calls) override;
3199  void Update(ResourceBinder* rb) override;
3200  ResourceType GetType() const override { return kShaderProgram; }
3201 
3203  void Bind(ResourceBinder* rb);
3204  void Unbind(ResourceBinder* rb) override;
3205 
3206  const ShaderProgram& GetShaderProgram() const {
3207  return static_cast<const ShaderProgram&>(*GetHolder());
3208  }
3209 
3211  ShaderResource* GetVertexResource() const { return vertex_resource_; }
3212  ShaderResource* GetFragmentResource() const { return fragment_resource_; }
3213 
3214  private:
3215  struct UniformCacheEntry {
3216  UniformCacheEntry()
3217  : location(-1),
3218  spec(nullptr),
3219  uniform_stamp(base::kInvalidIndex),
3220  unit_associations(
3221  base::AllocationManager::GetDefaultAllocatorForLifetime(
3222  base::kMediumTerm)) {}
3223  UniformCacheEntry(GLint location_in, GLint array_size,
3224  const ShaderInputRegistry::UniformSpec* spec_in)
3225  : location(location_in),
3226  spec(spec_in),
3227  uniform_stamp(base::kInvalidIndex),
3228  unit_associations(
3229  base::AllocationManager::GetDefaultAllocatorForLifetime(
3230  base::kMediumTerm),
3231  array_size, -1) {}
3232 
3233  const int& GetUnit(size_t index) {
3234  DCHECK_LT(index, unit_associations.size());
3235  return unit_associations[index];
3236  }
3237  void SetUnit(size_t index, int unit) {
3238  DCHECK_LT(index, unit_associations.size());
3239  unit_associations[index] = unit;
3240  }
3241 
3242  GLint location; // If location is -1 then the value is not valid.
3244  uint64 uniform_stamp;
3246  base::AllocVector<int> unit_associations;
3247  };
3248 
3249  typedef base::AllocUnorderedMap<const ShaderInputRegistry::AttributeSpec*,
3250  GLint> AttributeIndexMap;
3251 
3254  void PopulateAttributeCache(GLuint id, const std::string& id_string,
3255  const ShaderInputRegistryPtr& reg,
3256  GraphicsManager* gm);
3257 
3261  void PopulateUniformCache();
3262 
3264  void UpdateUniformValues(ResourceBinder* rb);
3265 
3268  bool UpdateUnitAssociations(UniformCacheEntry* entry,
3269  ResourceBinder* rb,
3270  const Uniform& new_uniform);
3271 
3274  bool UpdateUnitAssociationAndBind(TextureResource* txr,
3275  UniformCacheEntry* entry,
3276  ResourceBinder* rb,
3277  size_t array_index);
3278 
3281  bool ContainsAnEvictedTexture(const Uniform& uniform, ResourceBinder* rb);
3282 
3284  AttributeIndexMap attribute_index_map_;
3285 
3287  base::AllocVector<UniformCacheEntry> uniforms_;
3288 
3290  ShaderResource* vertex_resource_;
3291  ShaderResource* fragment_resource_;
3292 };
3293 
3294 void Renderer::ShaderProgramResource::PopulateAttributeCache(
3295  GLuint id, const std::string& id_string, const ShaderInputRegistryPtr& reg,
3296  GraphicsManager* gm) {
3297  GLint max_length = 0;
3298  GLint attribute_count = 0;
3300  gm->GetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &attribute_count);
3301  if (attribute_count) {
3302  attribute_index_map_.clear();
3303 
3304  gm->GetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_length);
3305  static const GLint kMaxNameLength = 4096;
3306  char name[kMaxNameLength];
3308  max_length =
3309  std::min(kMaxNameLength, max_length == 0 ? kMaxNameLength : max_length);
3310 
3313  GLsizei length;
3314  GLint size;
3315  GLuint type;
3316  const base::AllocatorPtr& allocator =
3317  GetShaderProgram().GetAllocator()->GetAllocatorForLifetime(
3319  base::AllocVector<GLenum> buffer_types(allocator);
3320  base::AllocVector<GLenum> simple_types(allocator);
3321  base::AllocVector<const ShaderInputRegistry::AttributeSpec*>
3322  buffer_attributes(allocator);
3323  base::AllocVector<const ShaderInputRegistry::AttributeSpec*>
3324  simple_attributes(allocator);
3325  for (GLint i = 0; i < attribute_count; ++i) {
3327  name[0] = 0;
3328  gm->GetActiveAttrib(id, i, max_length, &length, &size, &type, name);
3329  if (const ShaderInputRegistry::AttributeSpec* spec =
3330  reg->Find<Attribute>(name)) {
3331  if (spec->value_type == kBufferObjectElementAttribute) {
3332  buffer_attributes.push_back(spec);
3333  buffer_types.push_back(type);
3334  } else {
3335  simple_attributes.push_back(spec);
3336  simple_types.push_back(type);
3337  }
3338  } else {
3342  if (strcmp(name, "gl_InstanceID") != 0) {
3343  LOG(WARNING) << "***ION: Attribute '" << name << "' used in shader '"
3344  << GetShaderProgram().GetLabel()
3345  << "' does not have a registry entry";
3346  }
3347  }
3348  }
3349 
3351  GLuint attribute_index = 0;
3352  GLuint count = static_cast<GLuint>(buffer_attributes.size());
3353  for (GLuint i = 0; i < count; ++i) {
3354  attribute_index_map_[buffer_attributes[i]] =
3355  static_cast<GLint>(attribute_index);
3356  gm->BindAttribLocation(id, attribute_index,
3357  buffer_attributes[i]->name.c_str());
3358  attribute_index += GetAttributeSlotCountByGlType(buffer_types[i]);
3359  }
3360  count = static_cast<GLuint>(simple_attributes.size());
3361  for (GLuint i = 0; i < count; ++i) {
3362  attribute_index_map_[simple_attributes[i]] =
3363  static_cast<GLint>(attribute_index);
3364  gm->BindAttribLocation(id, attribute_index,
3365  simple_attributes[i]->name.c_str());
3366  attribute_index += GetAttributeSlotCountByGlType(simple_types[i]);
3367  }
3368  }
3369 }
3370 
3371 void Renderer::ShaderProgramResource::PopulateUniformCache() {
3372  const ShaderProgram& shader_program = GetShaderProgram();
3373  const ShaderInputRegistryPtr& reg = shader_program.GetRegistry();
3374  GraphicsManager* gm = GetGraphicsManager();
3375 
3376  GLint max_length = 0;
3377  GLuint uniform_count = 0;
3379  gm->GetProgramiv(id_, GL_ACTIVE_UNIFORMS,
3380  reinterpret_cast<GLint*>(&uniform_count));
3381  uniforms_.clear();
3382  if (uniform_count) {
3383  gm->GetProgramiv(id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_length);
3384  static const GLint kMaxNameLength = 4096;
3385  char name[kMaxNameLength];
3387  max_length =
3388  std::min(kMaxNameLength, max_length == 0 ? kMaxNameLength : max_length);
3389  GLsizei length;
3390  GLint size;
3391  uniforms_.reserve(uniform_count);
3392  for (GLuint i = 0; i < uniform_count; ++i) {
3394  name[0] = 0;
3395  GLenum type;
3396  gm->GetActiveUniform(id_, i, max_length, &length, &size, &type, name);
3397 
3399  for (int i = 0; i < kMaxNameLength; i++) {
3400  if (name[i] == '[' || name[i] == 0) {
3401  name[i] = 0;
3402  break;
3403  }
3404  }
3405 
3407  if (const ShaderInputRegistry::UniformSpec* spec =
3408  reg->Find<Uniform>(name)) {
3410  if (!ValidateUniformType(name, spec->value_type, type)) {
3411  TracingHelper helper;
3412  LOG(WARNING) << "***ION: Uniform '" << name << "' has a"
3413  << " different type from its spec: spec type: "
3414  << spec->value_type
3415  << ", uniform type: " << helper.ToString("GLenum", type);
3416  }
3417 
3418  const int location = gm->GetUniformLocation(id_, name);
3421  uniforms_.push_back(UniformCacheEntry(location, size, spec));
3422  } else {
3424  LOG(WARNING) << "***ION: Uniform '" << name << "' used in shader '"
3425  << shader_program.GetLabel()
3426  << "' does not have a registry entry";
3427  }
3428  }
3429  }
3430 }
3431 
3432 bool Renderer::ShaderProgramResource::ContainsAnEvictedTexture(
3433  const Uniform& uniform, ResourceBinder* rb) {
3434  bool ret = false;
3435  if (uniform.IsValid()) {
3436  if (uniform.GetType() == kCubeMapTextureUniform) {
3437  if (const size_t count = uniform.GetCount()) {
3438  for (size_t i = 0; i < count; ++i) {
3439  if (TextureResource* txr = GetResource(
3440  uniform.GetValueAt<CubeMapTexturePtr>(i).Get(), rb)) {
3441  if (rb->WasTextureEvicted(txr)) {
3442  ret = true;
3443  break;
3444  }
3445  }
3446  }
3447  } else if (TextureResource* txr = GetResource(
3448  uniform.GetValue<CubeMapTexturePtr>().Get(), rb)) {
3449  ret = rb->WasTextureEvicted(txr);
3450  }
3451  } else if (uniform.GetType() == kTextureUniform) {
3452  if (const size_t count = uniform.GetCount()) {
3453  for (size_t i = 0; i < count; ++i) {
3454  if (TextureResource* txr =
3455  GetResource(uniform.GetValueAt<TexturePtr>(i).Get(), rb)) {
3456  if (rb->WasTextureEvicted(txr)) {
3457  ret = true;
3458  break;
3459  }
3460  }
3461  }
3462  } else if (TextureResource* txr =
3463  GetResource(uniform.GetValue<TexturePtr>().Get(), rb)) {
3464  ret = rb->WasTextureEvicted(txr);
3465  }
3466  }
3467  }
3468  return ret;
3469 }
3470 
3471 bool Renderer::ShaderProgramResource::UpdateUnitAssociations(
3472  UniformCacheEntry* entry, ResourceBinder* rb, const Uniform& u) {
3473  bool changed = false;
3474  if (u.GetType() == kCubeMapTextureUniform) {
3475  if (const size_t count = u.GetCount()) {
3476  for (size_t i = 0; i < count; ++i) {
3477  if (TextureResource* txr =
3478  GetResource(u.GetValueAt<CubeMapTexturePtr>(i).Get(), rb)) {
3479  changed = UpdateUnitAssociationAndBind(txr, entry, rb, i) || changed;
3480  }
3481  }
3482  } else if (TextureResource* txr =
3483  GetResource(u.GetValue<CubeMapTexturePtr>().Get(), rb)) {
3484  changed = UpdateUnitAssociationAndBind(txr, entry, rb, 0);
3485  }
3486  } else if (u.GetType() == kTextureUniform) {
3487  if (const size_t count = u.GetCount()) {
3488  for (size_t i = 0; i < count; ++i) {
3489  if (TextureResource* txr =
3490  GetResource(u.GetValueAt<TexturePtr>(i).Get(), rb)) {
3491  changed = UpdateUnitAssociationAndBind(txr, entry, rb, i) || changed;
3492  }
3493  }
3494  } else if (TextureResource* txr =
3495  GetResource(u.GetValue<TexturePtr>().Get(), rb)) {
3496  changed = UpdateUnitAssociationAndBind(txr, entry, rb, 0);
3497  }
3498  }
3499  return changed;
3500 }
3501 
3502 bool Renderer::ShaderProgramResource::UpdateUnitAssociationAndBind(
3503  TextureResource* txr, UniformCacheEntry* entry, ResourceBinder* rb,
3504  size_t array_index) {
3509  const int& cached_unit = entry->GetUnit(array_index);
3511  const int last_unit_sent = cached_unit;
3512  const int new_unit =
3513  static_cast<int>(txr->ObtainImageUnit(rb, &cached_unit, cached_unit));
3515  txr->BindToUnit(rb, new_unit);
3516  entry->SetUnit(array_index, new_unit);
3517 
3520  return cached_unit != last_unit_sent;
3521 }
3522 
3523 void Renderer::ShaderProgramResource::UpdateUniformValues(ResourceBinder* rb) {
3524  GraphicsManager* gm = GetGraphicsManager();
3525 
3526  const size_t uniform_count = uniforms_.size();
3527  for (size_t i = 0; i < uniform_count; ++i) {
3528  UniformCacheEntry& entry = uniforms_[i];
3529  ShaderInputRegistryResource* sirr = GetResource(entry.spec->registry, rb);
3530  sirr->Update(rb);
3531 
3534  const Uniform& uniform = sirr->GetUniform(entry.spec->index);
3535  if (!uniform.IsValid()) {
3536  if (!rb->IsProcessingInfoRequests()) {
3537  LOG(WARNING) << "***ION: There is no value set for uniform '"
3538  << entry.spec->name << "' for shader program '"
3539  << GetShaderProgram().GetLabel() << "', rendering"
3540  << " results may be unexpected";
3541  }
3542  return;
3543  }
3550  bool skip_sending_uniform = false;
3551  bool unit_changed = false;
3552  if (uniform.GetType() == kTextureUniform ||
3553  uniform.GetType() == kCubeMapTextureUniform) {
3555  unit_changed = UpdateUnitAssociations(&entry, rb, uniform);
3556  skip_sending_uniform = !unit_changed;
3557  }
3562  if (unit_changed || // Texture unit changed.
3563  entry.uniform_stamp != uniform.GetStamp() ||
3564  ContainsAnEvictedTexture(uniform, rb)) {
3566  entry.uniform_stamp = uniform.GetStamp();
3568  ScopedLabel label(rb, &uniform, entry.spec->name);
3569  if (!skip_sending_uniform) {
3571  rb->SendUniform(uniform, entry.location, gm);
3572  }
3573  }
3574  }
3575 }
3576 
3577 void Renderer::ShaderProgramResource::Update(ResourceBinder* rb) {
3579  if (TestModifiedBit(ShaderProgram::kVertexShaderChanged))
3580  vertex_resource_ = nullptr;
3581  if (TestModifiedBit(ShaderProgram::kFragmentShaderChanged))
3582  fragment_resource_ = nullptr;
3584  const bool vertex_updated =
3585  vertex_resource_ && vertex_resource_->UpdateShader(rb);
3586  const bool fragment_updated =
3587  fragment_resource_ && fragment_resource_->UpdateShader(rb);
3588  if (vertex_updated || fragment_updated || AnyModifiedBitsSet()) {
3589  ScopedResourceLabel label(this, rb);
3590  const ShaderProgram& shader_program = GetShaderProgram();
3591 
3592  if (!vertex_resource_) {
3593  if (Shader* shader = shader_program.GetVertexShader().Get()) {
3594  if ((vertex_resource_ = GetResource(shader, rb), rb)) {
3595  vertex_resource_->SetShaderType(GL_VERTEX_SHADER);
3596  vertex_resource_->UpdateShader(rb);
3597  }
3598  }
3599  }
3600  if (!fragment_resource_) {
3601  if (Shader* shader = shader_program.GetFragmentShader().Get()) {
3602  if ((fragment_resource_ = GetResource(shader, rb))) {
3603  fragment_resource_->SetShaderType(GL_FRAGMENT_SHADER);
3604  fragment_resource_->UpdateShader(rb);
3605  }
3606  }
3607  }
3608 
3609  const GLuint vertex_shader_id =
3610  vertex_resource_ ? vertex_resource_->GetId() : 0;
3611  const GLuint fragment_shader_id =
3612  fragment_resource_ ? fragment_resource_->GetId() : 0;
3613 
3615  const std::string& id_string = shader_program.GetLabel();
3616  GraphicsManager* gm = GetGraphicsManager();
3617 
3618  std::string info_log = shader_program.GetInfoLog();
3619  GLuint id = LinkShaderProgram(id_string, vertex_shader_id,
3620  fragment_shader_id, &info_log, gm);
3621 
3622  if (id != 0) {
3625  const ShaderInputRegistryPtr& reg = shader_program.GetRegistry();
3627  if (!reg->CheckInputsAreUnique()) {
3628  LOG(WARNING) << "***ION: Registry '" << reg->GetId() << " contains"
3629  << " multiple definitions of some inputs, rendering"
3630  << " results may be unexpected";
3631  }
3632 
3634  PopulateAttributeCache(id, id_string, reg, gm);
3635 
3637  id = RelinkShaderProgram(id_string, id, vertex_shader_id,
3638  fragment_shader_id, &info_log, gm);
3639  bool need_to_update_label =
3640  vertex_updated || fragment_updated ||
3641  TestModifiedBit(ResourceHolder::kLabelChanged);
3642  if (id != 0) {
3643  id_ = id;
3644  need_to_update_label = true;
3645  }
3646 
3649  PopulateUniformCache();
3650 
3653  if (need_to_update_label)
3654  SetObjectLabel(gm, GL_PROGRAM_OBJECT, id_, shader_program.GetLabel());
3655  }
3656 
3658  shader_program.SetInfoLog(info_log);
3659  ResetModifiedBits();
3660  }
3661 }
3662 
3663 void Renderer::ShaderProgramResource::Bind(ResourceBinder* rb) {
3664  Update(rb);
3665  if (id_) {
3666  ScopedResourceLabel label(this, rb);
3667  rb->BindProgram(id_, this);
3669  UpdateUniformValues(rb);
3670  }
3671 }
3672 
3673 void Renderer::ShaderProgramResource::Unbind(ResourceBinder* rb) {
3674  if (rb)
3675  rb->ClearProgramBinding(id_);
3676 }
3677 
3678 void Renderer::ShaderProgramResource::Release(bool can_make_gl_calls) {
3679  BaseResourceType::Release(can_make_gl_calls);
3680  if (id_) {
3682  base::ReadLock read_lock(GetResourceBinderLock());
3683  base::ReadGuard read_guard(&read_lock);
3684  ResourceBinderMap& binders = GetResourceBinderMap();
3685  for (ResourceBinderMap::iterator it = binders.begin();
3686  it != binders.end();
3687  ++it) {
3688  Unbind(it->second.get());
3689  it->second->EraseVertexArrayKey(this);
3690  }
3691 
3692  if (resource_owns_gl_id_ && can_make_gl_calls)
3693  GetGraphicsManager()->DeleteProgram(id_);
3694  id_ = 0;
3695  }
3696 }
3697 
3699 
3704 
3705 
3706 class Renderer::BufferResource : public Resource<BufferObject::kNumChanges> {
3707  public:
3708  BufferResource(ResourceBinder* rb, ResourceManager* rm,
3709  const BufferObject& buffer_object, ResourceKey key, GLuint id)
3710  : Renderer::Resource<BufferObject::kNumChanges>(rm, buffer_object, key,
3711  id),
3712  target_(buffer_object.GetTarget()),
3713  gl_target_(base::EnumHelper::GetConstant(target_)) {}
3714 
3715  ~BufferResource() override {
3716  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
3717  }
3718 
3719  void Release(bool can_make_gl_calls) override;
3720  void Update(ResourceBinder* rb) override;
3721  ResourceType GetType() const override { return kBufferObject; }
3722 
3724  void Bind(ResourceBinder* rb);
3725  void Unbind(ResourceBinder* rb) override;
3726 
3727  GLuint GetGlTarget() const { return gl_target_; }
3728 
3729  void UploadData();
3730  void UploadSubData(const Range1ui& range, const void* data) const;
3731  void CopySubData(ResourceBinder* rb,
3732  BufferResource* src_resource,
3733  const Range1ui& range,
3734  uint32 read_offset);
3735 
3736  void OnDestroyed() override {
3737  if (target_ == BufferObject::kElementBuffer)
3738  GetResourceManager()->DisassociateElementBufferFromArrays(this);
3739  UnbindAll();
3740  Renderer::Resource<BufferObject::kNumChanges>::OnDestroyed();
3741  }
3742 
3743  private:
3744  const BufferObject& GetBufferObject() const {
3745  return static_cast<const BufferObject&>(*GetHolder());
3746  }
3747 
3748  BufferObject::Target target_;
3749  GLuint gl_target_;
3750 };
3751 
3752 void Renderer::BufferResource::Bind(ResourceBinder* rb) {
3753  Update(rb);
3754  if (id_) {
3755  ScopedResourceLabel label(this, rb);
3756  rb->BindBuffer(target_, id_, this);
3757  }
3758 }
3759 
3760 void Renderer::BufferResource::UploadData() {
3761  const BufferObject& bo = GetBufferObject();
3762  const size_t size = bo.GetStructSize() * bo.GetCount();
3763  SetUsedGpuMemory(size);
3764  GetGraphicsManager()->BufferData(
3765  gl_target_, size, bo.GetData().Get() ? bo.GetData()->GetData() : nullptr,
3766  base::EnumHelper::GetConstant(bo.GetUsageMode()));
3767 }
3768 
3769 void Renderer::BufferResource::UploadSubData(const Range1ui& range,
3770  const void* data) const {
3771  GetGraphicsManager()->BufferSubData(
3772  gl_target_, range.GetMinPoint(), range.GetSize(), data);
3773 }
3774 
3775 void Renderer::BufferResource::CopySubData(ResourceBinder* rb,
3776  BufferResource* src_resource,
3777  const Range1ui& range,
3778  uint32 read_offset) {
3779  if (!src_resource || src_resource == this) {
3781  GetGraphicsManager()->CopyBufferSubData(
3782  gl_target_, gl_target_, read_offset, range.GetMinPoint(),
3783  range.GetSize());
3784  } else {
3787  GLuint src_id = src_resource->GetId();
3788  rb->BindBuffer(BufferObject::kCopyReadBuffer, src_id, src_resource);
3789  rb->BindBuffer(BufferObject::kCopyWriteBuffer, id_, this);
3790  GetGraphicsManager()->CopyBufferSubData(
3791  GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
3792  read_offset, range.GetMinPoint(), range.GetSize());
3793  }
3794 }
3795 
3796 void Renderer::BufferResource::Update(ResourceBinder* rb) {
3797  if (!AnyModifiedBitsSet()) {
3798  return;
3799  }
3800  ScopedResourceLabel label(this, rb);
3801 
3803  GraphicsManager* gm = GetGraphicsManager();
3804  DCHECK(gm);
3805  if (!id_)
3806  gm->GenBuffers(1, &id_);
3807  if (!id_) {
3808  LOG(ERROR) << "***ION: Unable to create buffer object";
3809  return;
3810  }
3813  if (TestModifiedBit(ResourceHolder::kResourceChanged))
3814  rb->ClearBufferBinding(target_, id_);
3815 
3817  const BufferObject& bo = GetBufferObject();
3818  if (!bo.GetStructSize()) {
3819  LOG(WARNING) << "***ION: Unable to update buffer object \""
3820  << bo.GetLabel() << "\": BufferObject's"
3821  << " struct size is 0";
3822  return;
3823  }
3824  if (!bo.GetCount()) {
3825  LOG(WARNING) << "***ION: Unable to update buffer object \""
3826  << bo.GetLabel() << "\": BufferObject's"
3827  << " struct count is 0";
3828  return;
3829  }
3830  DCHECK_LT(0U, bo.GetCount());
3831  rb->BindBuffer(target_, id_, this);
3832 
3833  const bool data_changed = TestModifiedBit(BufferObject::kDataChanged);
3834  const bool label_changed = TestModifiedBit(ResourceHolder::kLabelChanged);
3835  const bool subdata_changed = TestModifiedBit(BufferObject::kSubDataChanged);
3838  ResetModifiedBits();
3839 
3840  if (data_changed) {
3841  UploadData();
3844  if (bo.GetData().Get())
3845  bo.GetData()->WipeData();
3846  }
3847  if (label_changed)
3848  SetObjectLabel(gm, GL_BUFFER_OBJECT, id_, bo.GetLabel());
3849 
3850  if (subdata_changed) {
3851  const base::AllocVector<BufferObject::BufferSubData>& sub_data =
3852  bo.GetSubData();
3853  const size_t count = sub_data.size();
3854  for (size_t i = 0; i < count; ++i) {
3855  const BufferObject::BufferSubData& sdata = sub_data[i];
3856  if (sdata.data.Get() && sdata.data->GetData()) {
3857  UploadSubData(
3858  sdata.range, sdata.data->GetData<uint8>() + sdata.read_offset);
3861  sdata.data->WipeData();
3862  continue;
3863  }
3866  BufferResource* src_resource = nullptr;
3867  if (sdata.src.Get()) {
3868  src_resource = GetResource(sdata.src.Get(), rb);
3869  DCHECK(src_resource);
3871  src_resource->Update(rb);
3872  }
3873  if (gm->IsFunctionGroupAvailable(GraphicsManager::kCopyBufferSubData)) {
3874  CopySubData(rb, src_resource, sdata.range, sdata.read_offset);
3875  continue;
3876  }
3879  Range1ui read_range;
3880  read_range.SetWithSize(sdata.read_offset, sdata.range.GetSize());
3881  const Range1ui& write_range = sdata.range;
3882  BufferObjectPtr dst(const_cast<BufferObject*>(&bo));
3883  BufferObjectPtr src(sdata.src.Get() ? sdata.src : dst);
3884  Range1ui union_range;
3885  if (src == dst) {
3886  union_range = read_range;
3887  union_range.ExtendByRange(write_range);
3888  rb->MapBufferObjectDataRange(src, kReadWrite, union_range);
3889  } else {
3890  rb->MapBufferObjectDataRange(src, kReadOnly, read_range);
3891  }
3892  switch (src->GetMappedData().data_source) {
3893  case BufferObject::MappedBufferData::kGpuMapped:
3894  case BufferObject::MappedBufferData::kDataContainer:
3895  if (src == dst) {
3896  uint8* data = static_cast<uint8*>(src->GetMappedPointer());
3897  memcpy(data +
3898  write_range.GetMinPoint() - union_range.GetMinPoint(),
3899  data +
3900  read_range.GetMinPoint() - union_range.GetMinPoint(),
3901  write_range.GetSize());
3902  } else {
3903  rb->MapBufferObjectDataRange(dst, kWriteOnly, write_range);
3904  memcpy(dst->GetMappedPointer(), src->GetMappedPointer(),
3905  write_range.GetSize());
3907  rb->UnmapBufferObjectData(dst);
3908  }
3909  break;
3910  case BufferObject::MappedBufferData::kAllocated:
3911  LOG(WARNING) << "***ION: Unable to copy buffer object \""
3912  << src->GetLabel() << "\": BufferObject's"
3913  << " DataContainer has been wiped and "
3914  << " glCopyBufferSubData is not supported.";
3915  break;
3916  default:
3918  "Invalid source for mapped BufferObject data";
3919  break;
3920  }
3921  rb->UnmapBufferObjectData(src);
3922  }
3923  bo.ClearSubData();
3924  }
3925 }
3926 
3927 void Renderer::BufferResource::Unbind(ResourceBinder* rb) {
3932  if (rb)
3933  rb->ClearBufferBinding(target_, id_);
3934 }
3935 
3936 void Renderer::BufferResource::Release(bool can_make_gl_calls) {
3937  BaseResourceType::Release(can_make_gl_calls);
3938  if (id_) {
3939  UnbindAll();
3940  if (resource_owns_gl_id_ && can_make_gl_calls)
3941  GetGraphicsManager()->DeleteBuffers(1, &id_);
3942  SetUsedGpuMemory(0U);
3943  id_ = 0;
3944  }
3945 }
3946 
3948 
3953 
3954 
3955 class Renderer::FramebufferResource
3956  : public Resource<FramebufferObject::kNumChanges> {
3957  public:
3958  FramebufferResource(ResourceBinder* rb, ResourceManager* rm,
3959  const FramebufferObject& fbo, ResourceKey key, GLuint id)
3960  : Renderer::Resource<FramebufferObject::kNumChanges>(rm, fbo, key, id),
3961  color0_id_(0U),
3962  depth_id_(0U),
3963  stencil_id_(0U) {}
3964 
3965  ~FramebufferResource() override {
3966  DCHECK((id_ == 0U && color0_id_ == 0U &&
3967  depth_id_ == 0U && stencil_id_ == 0U) ||
3969  }
3970 
3971  void Release(bool can_make_gl_calls) override;
3972  void Update(ResourceBinder* rb) override;
3973  ResourceType GetType() const override { return kFramebufferObject; }
3974 
3976  virtual void Bind(ResourceBinder* rb);
3977  void Unbind(ResourceBinder* rb) override;
3978  void OnDestroyed() override {
3979  Resource<FramebufferObject::kNumChanges>::OnDestroyed();
3980  UnbindAll();
3981  }
3982 
3983  GLuint GetColor0Id() const { return color0_id_; }
3984  GLuint GetDepthId() const { return depth_id_; }
3985  GLuint GetStencilId() const { return stencil_id_; }
3986 
3987  private:
3988  const FramebufferObject& GetFramebufferObject() const {
3989  return static_cast<const FramebufferObject&>(*GetHolder());
3990  }
3991 
3992  void UpdateAttachment(GraphicsManager* gm, ResourceBinder* rb, GLuint* id,
3993  GLenum target, const FramebufferObject& fbo,
3994  const FramebufferObject::Attachment& attachment);
3995 
3996  void UpdateMemoryUsage(const FramebufferObject& fbo);
3997 
3999  GLuint color0_id_;
4000  GLuint depth_id_;
4001  GLuint stencil_id_;
4002 };
4003 
4004 void Renderer::FramebufferResource::Bind(ResourceBinder* rb) {
4005  Update(rb);
4006  ScopedResourceLabel label(this, rb);
4007  rb->BindFramebuffer(id_, this);
4008 }
4009 
4010 void Renderer::FramebufferResource::UpdateAttachment(
4011  GraphicsManager* gm, ResourceBinder* rb, GLuint* id, GLenum target,
4012  const FramebufferObject& fbo,
4013  const FramebufferObject::Attachment& attachment) {
4014  if (attachment.GetBinding() == FramebufferObject::kUnbound) {
4017  gm->FramebufferRenderbuffer(GL_FRAMEBUFFER, target, GL_RENDERBUFFER, 0);
4018  } else if (attachment.GetBinding() == FramebufferObject::kRenderbuffer) {
4020  if (!*id)
4021  gm->GenRenderbuffers(1, id);
4022  if (*id) {
4024  gm->BindRenderbuffer(GL_RENDERBUFFER, *id);
4025  if (attachment.GetSamples() > 0) {
4026  gm->RenderbufferStorageMultisample(
4027  GL_RENDERBUFFER,
4028  static_cast<GLsizei>(attachment.GetSamples()),
4029  Image::GetPixelFormat(attachment.GetFormat()).internal_format,
4030  fbo.GetWidth(), fbo.GetHeight());
4031  } else {
4032  ImagePtr image = attachment.GetImage();
4033  if (image.Get() && (image->GetType() == Image::kEgl ||
4034  image->GetType() == Image::kExternalEgl)) {
4035  const DataContainerPtr& container = image->GetData();
4036  const void* data = container.Get() ? container->GetData() : nullptr;
4037  if (data &&
4038  gm->IsFunctionGroupAvailable(GraphicsManager::kEglImage)) {
4039  gm->EGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
4040  const_cast<void*>(data));
4041  }
4042  } else {
4043  gm->RenderbufferStorage(
4044  GL_RENDERBUFFER,
4045  Image::GetPixelFormat(attachment.GetFormat()).internal_format,
4046  fbo.GetWidth(), fbo.GetHeight());
4047  }
4048  }
4049  } else {
4050  LOG(ERROR) << "***ION: Unable to create renderbuffer object.";
4051  }
4053  gm->FramebufferRenderbuffer(GL_FRAMEBUFFER, target, GL_RENDERBUFFER, *id);
4054  } else if (attachment.GetBinding() == FramebufferObject::kCubeMapTexture) {
4055  DCHECK_EQ(FramebufferObject::kCubeMapTexture, attachment.GetBinding());
4056  DCHECK(attachment.GetCubeMapTexture().Get());
4057 
4059  CubeMapTexture* tex = attachment.GetCubeMapTexture().Get();
4060  TextureResource* tr = GetResource(tex, rb);
4061  DCHECK(tr);
4062  const CubeMapTexture::CubeFace face = attachment.GetCubeMapFace();
4066  const size_t mip_level = attachment.GetMipLevel();
4067  ImagePtr image = tex->GetImage(face, mip_level);
4068  if (image.Get()) {
4069  format = image->GetFormat();
4070  if (format != Image::kEglImage &&
4071  (image->GetWidth() != fbo.GetWidth() ||
4072  image->GetHeight() != fbo.GetHeight())) {
4073  LOG(ERROR) << "***ION: Mismatched CubeMapTexture and FBO dimensions: "
4074  << image->GetWidth() << " x " << image->GetHeight()
4075  << " vs. "
4076  << fbo.GetWidth() << " x " << fbo.GetHeight();
4077  }
4078  } else {
4079  image = new(GetAllocatorForLifetime(base::kMediumTerm)) Image;
4084  image->Set(format, fbo.GetWidth(), fbo.GetHeight(),
4085  DataContainerPtr(nullptr));
4086  tex->SetImage(face, mip_level, image);
4087  }
4088  tr->Bind(rb);
4090  gm->FramebufferTexture2D(GL_FRAMEBUFFER, target,
4091  base::EnumHelper::GetConstant(face), tr->GetId(),
4092  static_cast<GLint>(mip_level));
4093  } else {
4094  DCHECK_EQ(FramebufferObject::kTexture, attachment.GetBinding());
4095  DCHECK(attachment.GetTexture().Get());
4096 
4098  Texture* tex = attachment.GetTexture().Get();
4099  TextureResource* tr = GetResource(tex, rb);
4100  DCHECK(tr);
4104  const size_t mip_level = attachment.GetMipLevel();
4105  ImagePtr image = tex->GetImage(mip_level);
4106  if (image.Get()) {
4107  format = image->GetFormat();
4108  if (format != Image::kEglImage &&
4109  (image->GetWidth() != fbo.GetWidth() ||
4110  image->GetHeight() != fbo.GetHeight())) {
4111  LOG(ERROR) << "***ION: Mismatched Texture and FBO dimensions: "
4112  << image->GetWidth() << " x " << image->GetHeight()
4113  << " vs. "
4114  << fbo.GetWidth() << " x " << fbo.GetHeight();
4115  }
4116  } else {
4117  image = new(GetAllocatorForLifetime(base::kMediumTerm)) Image;
4122  image->Set(format, fbo.GetWidth(), fbo.GetHeight(),
4123  DataContainerPtr(nullptr));
4124  tex->SetImage(mip_level, image);
4125  }
4126  tr->Bind(rb);
4128  gm->FramebufferTexture2D(GL_FRAMEBUFFER, target, tr->GetGlTarget(),
4129  tr->GetId(), static_cast<GLint>(mip_level));
4130  }
4131 }
4132 
4133 void Renderer::FramebufferResource::UpdateMemoryUsage(
4134  const FramebufferObject& fbo) {
4135  size_t data_size = 0U;
4136  if (color0_id_)
4137  data_size += Image::ComputeDataSize(fbo.GetColorAttachment(0U).GetFormat(),
4138  fbo.GetWidth(), fbo.GetHeight());
4139  if (depth_id_)
4140  data_size += Image::ComputeDataSize(fbo.GetDepthAttachment().GetFormat(),
4141  fbo.GetWidth(), fbo.GetHeight());
4142  if (stencil_id_)
4143  data_size += Image::ComputeDataSize(fbo.GetStencilAttachment().GetFormat(),
4144  fbo.GetWidth(), fbo.GetHeight());
4145  SetUsedGpuMemory(data_size);
4146 }
4147 
4148 void Renderer::FramebufferResource::Update(ResourceBinder* rb) {
4149  if (AnyModifiedBitsSet()) {
4150  ScopedResourceLabel label(this, rb);
4151 
4153  GraphicsManager* gm = GetGraphicsManager();
4154  DCHECK(gm);
4155  if (!id_) gm->GenFramebuffers(1, &id_);
4156  if (id_) {
4157  const FramebufferObject& fbo = GetFramebufferObject();
4158 
4160  rb->BindFramebuffer(id_, this);
4162  if (TestModifiedBit(FramebufferObject::kColorAttachmentChanged) ||
4163  TestModifiedBit(FramebufferObject::kDimensionsChanged))
4164  UpdateAttachment(gm, rb, &color0_id_, GL_COLOR_ATTACHMENT0, fbo,
4165  fbo.GetColorAttachment(0U));
4166  if (TestModifiedBit(FramebufferObject::kDepthAttachmentChanged) ||
4167  TestModifiedBit(FramebufferObject::kDimensionsChanged))
4168  UpdateAttachment(gm, rb, &depth_id_, GL_DEPTH_ATTACHMENT, fbo,
4169  fbo.GetDepthAttachment());
4170  if (TestModifiedBit(FramebufferObject::kStencilAttachmentChanged) ||
4171  TestModifiedBit(FramebufferObject::kDimensionsChanged))
4172  UpdateAttachment(gm, rb, &stencil_id_, GL_STENCIL_ATTACHMENT, fbo,
4173  fbo.GetStencilAttachment());
4174  UpdateMemoryUsage(fbo);
4175 
4176  if (TestModifiedBit(ResourceHolder::kLabelChanged))
4177  SetObjectLabel(gm, GL_FRAMEBUFFER, id_, fbo.GetLabel());
4178 
4180  const GLenum status = gm->CheckFramebufferStatus(GL_FRAMEBUFFER);
4181  if (status != GL_FRAMEBUFFER_COMPLETE) {
4182  LOG(ERROR)
4183  << "***ION: Framebuffer is not complete (error code: 0x"
4184  << std::hex << status
4185  << ")! One of the attachments might have a zero width or "
4186  "height or a non-drawable format for that attachment type. It "
4187  "is also possible that a texture attachment violates some "
4188  "GL-implementation specific set of constraints. Check the FBO "
4189  "dimensions and try changing the texture state of texture "
4190  "attachments (e.g. try kNearest or kLinear filtering, don't use "
4191  "kRepeat wrapping, etc.).";
4192  }
4193  ResetModifiedBits();
4194  } else {
4195  LOG(ERROR) << "***ION: Unable to create framebuffer object.";
4196  }
4197  }
4198 }
4199 
4200 void Renderer::FramebufferResource::Unbind(ResourceBinder* rb) {
4201  if (rb)
4202  rb->ClearFramebufferBinding(id_);
4203 }
4204 
4205 void Renderer::FramebufferResource::Release(bool can_make_gl_calls) {
4206  BaseResourceType::Release(can_make_gl_calls);
4207  if (id_) {
4208  UnbindAll();
4210  if (can_make_gl_calls) {
4211  if (color0_id_ )
4212  GetGraphicsManager()->DeleteRenderbuffers(1, &color0_id_);
4213  if (depth_id_)
4214  GetGraphicsManager()->DeleteRenderbuffers(1, &depth_id_);
4215  if (stencil_id_)
4216  GetGraphicsManager()->DeleteRenderbuffers(1, &stencil_id_);
4218  if (resource_owns_gl_id_)
4219  GetGraphicsManager()->DeleteFramebuffers(1, &id_);
4220  }
4221  SetUsedGpuMemory(0U);
4222  color0_id_ = depth_id_ = stencil_id_ = id_ = 0;
4223  }
4224 }
4225 
4227 
4232 
4233 
4234 class Renderer::VertexArrayResource
4235  : public Resource<AttributeArray::kNumChanges> {
4236  public:
4237  VertexArrayResource(ResourceBinder* rb, ResourceManager* rm,
4238  const AttributeArray& attribute_array, ResourceKey key,
4239  GLuint id)
4240  : Renderer::Resource<AttributeArray::kNumChanges>(rm, attribute_array,
4241  key, id),
4242  buffer_attribute_infos_(attribute_array.GetAllocator()),
4243  simple_attribute_indices_(attribute_array.GetAllocator()),
4244  vertex_count_(0U) {
4245  PopulateAttributeIndices(rb);
4246  }
4247 
4248  ~VertexArrayResource() override {
4249  DCHECK(id_ == 0U || !portgfx::Visual::GetCurrent());
4250  }
4251 
4252  void Release(bool can_make_gl_calls) override;
4253  ResourceType GetType() const override { return kAttributeArray; }
4254 
4262  virtual bool BindAndCheckBuffers(bool force_bind, ResourceBinder* rb);
4263  void Unbind(ResourceBinder* rb) override;
4264 
4265  size_t GetVertexCount() const { return vertex_count_; }
4266  const ResourceBinder::BufferBinding& GetElementArrayBinding() const {
4267  return element_array_binding_;
4268  }
4269  void SetElementArrayBinding(GLuint id, BufferResource* resource) {
4270  element_array_binding_.buffer = id;
4271  element_array_binding_.resource = resource;
4272  }
4273 
4274  protected:
4275  const AttributeArray& GetAttributeArray() const {
4276  return static_cast<const AttributeArray&>(*GetHolder());
4277  }
4278 
4279  virtual bool UpdateAndCheckBuffers(ResourceBinder* rb);
4280 
4282  void BindSimpleAttributes();
4283 
4289  bool BindBufferObjectElementAttribute(GLuint attribute_index,
4290  const Attribute& a, GLuint* slots,
4291  ResourceBinder* rb);
4292 
4294  void ResetVertexCount() {
4295  vertex_count_ = std::numeric_limits<std::size_t>::max();
4296  }
4297 
4298  void UpdateVertexCount(const Attribute& a) {
4299  const BufferObjectPtr& bo = a.GetValue<BufferObjectElement>().buffer_object;
4300  if (bo.Get()) {
4301  if (!a.GetDivisor() ||
4302  !GetGraphicsManager()->IsFunctionGroupAvailable(
4307  vertex_count_ = std::min(vertex_count_, bo->GetCount());
4308  }
4309  }
4310  }
4311 
4312  protected:
4313  struct BufferAttributeInfo {
4314  BufferAttributeInfo() : index(kInvalidGluint), slots(0U), enabled(false) {}
4315  GLuint index;
4316  GLuint slots;
4317  bool enabled;
4318  };
4320  base::AllocVector<BufferAttributeInfo> buffer_attribute_infos_;
4321  base::AllocVector<GLuint> simple_attribute_indices_;
4322 
4323  private:
4326  virtual void Bind(ResourceBinder* rb) {
4327  Update(rb);
4328  BindAndCheckBuffers(true, rb);
4329  }
4330  void Update(ResourceBinder* rb) override {}
4331 
4333  void PopulateAttributeIndices(ResourceBinder* rb);
4334 
4335  size_t vertex_count_;
4336  ResourceBinder::BufferBinding element_array_binding_;
4337 
4339  friend class ResourceBinder;
4340  friend class ResourceManager;
4341 };
4342 
4343 void Renderer::VertexArrayResource::BindSimpleAttributes() {
4344  GraphicsManager* gm = GetGraphicsManager();
4345  const AttributeArray& aa = GetAttributeArray();
4346  const size_t attribute_count = aa.GetSimpleAttributeCount();
4347  DCHECK_EQ(attribute_count, simple_attribute_indices_.size());
4348  for (size_t i = 0; i < attribute_count; ++i) {
4349  const Attribute& a = aa.GetSimpleAttribute(i);
4350  DCHECK(a.IsValid());
4351  const GLuint& attribute_index = simple_attribute_indices_[i];
4352  if (attribute_index != static_cast<GLuint>(base::kInvalidIndex)) {
4353  switch (a.GetType()) {
4354  case kFloatAttribute:
4355  gm->VertexAttrib1fv(attribute_index, &a.GetValue<float>());
4356  break;
4358  gm->VertexAttrib2fv(attribute_index,
4359  a.GetValue<math::VectorBase2f>().Data());
4360  break;
4362  gm->VertexAttrib3fv(attribute_index,
4363  a.GetValue<math::VectorBase3f>().Data());
4364  break;
4366  gm->VertexAttrib4fv(attribute_index,
4367  a.GetValue<math::VectorBase4f>().Data());
4368  break;
4370  case kFloatMatrix2x2Attribute: {
4371  const math::Matrix2f mat =
4372  math::Transpose(a.GetValue<math::Matrix2f>());
4373  gm->VertexAttrib2fv(attribute_index, mat.Data());
4374  gm->VertexAttrib2fv(attribute_index + 1, &mat.Data()[2]);
4375  break;
4376  }
4377  case kFloatMatrix3x3Attribute: {
4378  const math::Matrix3f mat =
4379  math::Transpose(a.GetValue<math::Matrix3f>());
4380  gm->VertexAttrib3fv(attribute_index, mat.Data());
4381  gm->VertexAttrib3fv(attribute_index + 1, &mat.Data()[3]);
4382  gm->VertexAttrib3fv(attribute_index + 2, &mat.Data()[6]);
4383  break;
4384  }
4385  case kFloatMatrix4x4Attribute: {
4386  const math::Matrix4f mat =
4387  math::Transpose(a.GetValue<math::Matrix4f>());
4388  gm->VertexAttrib4fv(attribute_index, mat.Data());
4389  gm->VertexAttrib4fv(attribute_index + 1, &mat.Data()[4]);
4390  gm->VertexAttrib4fv(attribute_index + 2, &mat.Data()[8]);
4391  gm->VertexAttrib4fv(attribute_index + 3, &mat.Data()[12]);
4392  break;
4393  }
4394  default:
4395  break;
4396  }
4397  }
4398  }
4399 }
4400 
4401 bool Renderer::VertexArrayResource::BindBufferObjectElementAttribute(
4402  GLuint attribute_index, const Attribute& a, GLuint* slots,
4403  ResourceBinder* rb) {
4404  DCHECK(a.IsValid());
4405  GraphicsManager* gm = GetGraphicsManager();
4406  DCHECK(gm);
4407 
4409  const BufferObjectPtr& bo = a.GetValue<BufferObjectElement>().buffer_object;
4410  if (!bo.Get()) {
4412  LOG(WARNING) << "***ION: Unable to draw shape: "
4413  << "BufferObject or BufferObject DataContainer is nullptr";
4414  return false;
4415  }
4416 
4417  BufferResource* vbo = GetResource(bo.Get(), rb);
4418  DCHECK(vbo);
4420  vbo->Bind(rb);
4421 
4422  const size_t spec_index = a.GetValue<BufferObjectElement>().spec_index;
4425  const BufferObject::Spec& spec = bo->GetSpec(spec_index);
4427  const GLenum type = base::EnumHelper::GetConstant(spec.type);
4428 
4431  GLuint stride = 0U;
4432  GetAttributeSlotCountAndStride(spec.type, &stride, slots);
4433  for (GLuint i = 0; i < *slots; ++i) {
4434  gm->VertexAttribPointer(
4435  attribute_index + i, static_cast<GLuint>(spec.component_count), type,
4436  a.IsFixedPointNormalized() ? GL_TRUE : GL_FALSE,
4437  static_cast<GLuint>(bo->GetStructSize()),
4438  reinterpret_cast<const void*>(spec.byte_offset + i * stride));
4439  if (gm->IsFunctionGroupAvailable(GraphicsManager::kInstancedDrawing)) {
4440  gm->VertexAttribDivisor(attribute_index + i, a.GetDivisor());
4441  }
4442  }
4443  return true;
4444 }
4445 
4446 void Renderer::VertexArrayResource::PopulateAttributeIndices(
4447  ResourceBinder* rb) {
4451  const AttributeArray& aa = GetAttributeArray();
4452  const size_t buffer_attribute_count = aa.GetBufferAttributeCount();
4453  const size_t simple_attribute_count = aa.GetSimpleAttributeCount();
4454  buffer_attribute_infos_.resize(buffer_attribute_count);
4455  simple_attribute_indices_.resize(simple_attribute_count, kInvalidGluint);
4456 
4457  if (ShaderProgramResource* spr = rb->GetActiveShaderProgram()) {
4458  DCHECK(spr);
4459  for (size_t i = 0; i < buffer_attribute_count; ++i) {
4460  const Attribute& a = aa.GetBufferAttribute(i);
4461  DCHECK(a.IsValid());
4464  const GLint index = spr->GetAttributeIndex(spec);
4465  if (index >= 0) {
4466  buffer_attribute_infos_[i].index = static_cast<GLuint>(index);
4467  } else if (aa.IsBufferAttributeEnabled(i)) {
4468  LOG_ONCE(WARNING)
4469  << "***ION: Attribute array contains buffer attribute '"
4470  << spec->name << "' but the current shader program '"
4471  << spr->GetShaderProgram().GetLabel() << "' does not"
4472  << " declare or use it";
4473  }
4474  }
4475 
4476  for (size_t i = 0; i < simple_attribute_count; ++i) {
4477  const Attribute& a = aa.GetSimpleAttribute(i);
4478  DCHECK(a.IsValid());
4481  const GLint index = spr->GetAttributeIndex(spec);
4482  if (index >= 0) {
4483  simple_attribute_indices_[i] = static_cast<GLuint>(index);
4484  } else {
4485  LOG_ONCE(WARNING)
4486  << "***ION: Attribute array contains simple attribute '"
4487  << spec->name << "' but the current shader program '"
4488  << spr->GetShaderProgram().GetLabel() << "' does not"
4489  << " declare or use it";
4490  }
4491  }
4492  }
4493 }
4494 
4495 bool Renderer::VertexArrayResource::UpdateAndCheckBuffers(ResourceBinder* rb) {
4496  if (AnyModifiedBitsSet()) {
4497  ScopedResourceLabel label(this, rb);
4499  GraphicsManager* gm = GetGraphicsManager();
4500  DCHECK(gm);
4501  if (!id_) gm->GenVertexArrays(1, &id_);
4502 
4503  const AttributeArray& aa = GetAttributeArray();
4504  DCHECK_EQ(aa.GetBufferAttributeCount(), buffer_attribute_infos_.size());
4505  DCHECK_EQ(aa.GetSimpleAttributeCount(), simple_attribute_indices_.size());
4506 
4507  ResetVertexCount();
4508 
4509  if (id_) {
4512  if (TestModifiedBit(ResourceHolder::kResourceChanged))
4513  rb->ClearVertexArrayBinding(id_);
4514 
4515  rb->BindVertexArray(id_, this);
4517  const size_t buffer_attribute_count = aa.GetBufferAttributeCount();
4518  DCHECK_EQ(buffer_attribute_count, buffer_attribute_infos_.size());
4519  for (size_t i = 0; i < buffer_attribute_count; ++i) {
4520  const Attribute& a = aa.GetBufferAttribute(i);
4521  UpdateVertexCount(a);
4522  BufferAttributeInfo& info = buffer_attribute_infos_[i];
4523  if (info.index != static_cast<GLuint>(base::kInvalidIndex)) {
4524  if (TestModifiedBit(
4525  static_cast<int>(AttributeArray::kAttributeChanged + i)) &&
4526  !BindBufferObjectElementAttribute(info.index, a, &info.slots, rb))
4527  return false;
4529  if (TestModifiedBit(static_cast<int>(
4531  DCHECK_GT(info.slots, 0U);
4532  if (aa.IsBufferAttributeEnabled(i)) {
4533  for (GLuint j = 0; j < info.slots; ++j)
4534  gm->EnableVertexAttribArray(info.index + j);
4535  info.enabled = true;
4536  } else {
4537  for (GLuint j = 0; j < info.slots; ++j)
4538  gm->DisableVertexAttribArray(info.index + j);
4539  info.enabled = false;
4540  }
4541  }
4542  }
4543  }
4544 
4545  if (TestModifiedBit(ResourceHolder::kLabelChanged))
4546  SetObjectLabel(gm, GL_VERTEX_ARRAY_OBJECT, id_, aa.GetLabel());
4547 
4548  ResetModifiedBits();
4549  } else {
4550  LOG(ERROR) << "***ION: Unable to create vertex array";
4551  return false;
4552  }
4553  }
4556  rb->BindVertexArray(id_, this);
4557  BindSimpleAttributes();
4558  return true;
4559 }
4560 
4561 bool Renderer::VertexArrayResource::BindAndCheckBuffers(bool force_bind,
4562  ResourceBinder* rb) {
4565  if ((UpdateAndCheckBuffers(rb) || force_bind) && id_) {
4566  ScopedResourceLabel label(this, rb);
4567  rb->BindVertexArray(id_, this);
4568  return true;
4569  }
4570  return false;
4571 }
4572 
4573 void Renderer::VertexArrayResource::Unbind(ResourceBinder* rb) {
4574  if (rb)
4575  rb->ClearVertexArrayBinding(id_);
4576 }
4577 
4578 void Renderer::VertexArrayResource::Release(bool can_make_gl_calls) {
4579  BaseResourceType::Release(can_make_gl_calls);
4580  if (id_) {
4582  UnbindAll();
4583  if (resource_owns_gl_id_ && can_make_gl_calls)
4584  GetGraphicsManager()->DeleteVertexArrays(1, &id_);
4585  id_ = 0;
4586  }
4587 }
4588 
4590 
4595 
4596 
4597 class Renderer::VertexArrayEmulatorResource
4598  : public Renderer::VertexArrayResource {
4599  public:
4600  VertexArrayEmulatorResource(ResourceBinder* rb, ResourceManager* rm,
4601  const AttributeArray& attribute_array,
4602  ResourceKey key, GLuint id)
4603  : VertexArrayResource(rb, rm, attribute_array, key, id) {}
4604  ~VertexArrayEmulatorResource() override {}
4605 
4606  void Release(bool can_make_gl_calls) override;
4607  bool UpdateAndCheckBuffers(ResourceBinder* rb) override;
4608 
4610  bool BindAndCheckBuffers(bool force_bind, ResourceBinder* rb) override;
4611  void Unbind(ResourceBinder* rb) override;
4612 };
4613 
4614 bool Renderer::VertexArrayEmulatorResource::UpdateAndCheckBuffers(
4615  ResourceBinder* rb) {
4618  if (rb->GetActiveVertexArray() != this || AnyModifiedBitsSet()) {
4619  ResetModifiedBits();
4620 
4621  ScopedResourceLabel label(this, rb);
4622  rb->SetActiveVertexArray(this);
4623  BindSimpleAttributes();
4624  ResetVertexCount();
4625 
4626  GraphicsManager* gm = GetGraphicsManager();
4627  const AttributeArray& aa = GetAttributeArray();
4630  const size_t buffer_attribute_count = aa.GetBufferAttributeCount();
4631  DCHECK_EQ(buffer_attribute_count, buffer_attribute_infos_.size());
4632  for (size_t i = 0; i < buffer_attribute_count; ++i) {
4633  if (aa.IsBufferAttributeEnabled(i)) {
4634  const Attribute& a = aa.GetBufferAttribute(i);
4635  UpdateVertexCount(a);
4636  BufferAttributeInfo& info = buffer_attribute_infos_[i];
4637  if (info.index != static_cast<GLuint>(base::kInvalidIndex)) {
4638  if (!BindBufferObjectElementAttribute(info.index, a, &info.slots, rb))
4639  return false;
4641  DCHECK_GT(info.slots, 0U);
4642  for (GLuint j = 0; j < info.slots; ++j)
4643  gm->EnableVertexAttribArray(info.index);
4644  info.enabled = true;
4645  }
4646  }
4647  }
4648  }
4649  return true;
4650 }
4651 
4652 bool Renderer::VertexArrayEmulatorResource::BindAndCheckBuffers(
4653  bool force_bind, ResourceBinder* rb) {
4654  return UpdateAndCheckBuffers(rb);
4655 }
4656 
4657 void Renderer::VertexArrayEmulatorResource::Unbind(ResourceBinder* rb) {
4659  const bool can_make_gl_calls = portgfx::Visual::GetCurrent() != nullptr;
4660  if (rb && rb->GetActiveVertexArray() == this) {
4661  GraphicsManager* gm = GetGraphicsManager();
4664  const size_t buffer_attribute_count = buffer_attribute_infos_.size();
4665  for (size_t i = 0; i < buffer_attribute_count; ++i) {
4666  BufferAttributeInfo& info = buffer_attribute_infos_[i];
4667  if (info.enabled &&
4668  info.index != static_cast<GLuint>(base::kInvalidIndex)) {
4669  if (can_make_gl_calls) {
4670  for (GLuint j = 0; j < info.slots; ++j)
4671  gm->DisableVertexAttribArray(info.index);
4672  }
4673 
4674  info.enabled = false;
4675  }
4676  }
4677  rb->SetActiveVertexArray(nullptr);
4678  }
4679 }
4680 
4681 void Renderer::VertexArrayEmulatorResource::Release(bool can_make_gl_calls) {
4682  BaseResourceType::Release(can_make_gl_calls);
4683  UnbindAll();
4684 }
4685 
4687 
4692 
4693 
4695  : flags_(AllProcessFlags()),
4696  resource_manager_(new (GetAllocator()) ResourceManager(gm)) {
4697  DCHECK(gm.Get());
4698 
4700  default_shader_ =
4701  CreateDefaultShaderProgram(GetAllocatorForLifetime(base::kLongTerm));
4702 }
4703 
4705  size_t visual_id;
4706  ResourceBinder* resource_binder = GetInternalResourceBinder(&visual_id);
4707  if (visual_id == 0) {
4708  LOG(WARNING) << "***ION: renderer.cc: ~Renderer"
4709  << ": No Visual ID (invalid GL Context?)";
4710  }
4711  resource_manager_->DestroyAllResources();
4712  if (resource_binder)
4713  resource_binder->SetCurrentFramebuffer(FramebufferObjectPtr());
4714 }
4715 
4717  static const Flags flags(AllClearFlags() | AllProcessFlags() |
4719  return flags;
4720 }
4721 
4723  static const Flags flags((1 << kClearActiveTexture) |
4724  (1 << kClearArrayBuffer) |
4725  (1 << kClearCubemaps) |
4726  (1 << kClearElementArrayBuffer) |
4727  (1 << kClearFramebuffer) |
4728  (1 << kClearShaderProgram) |
4729  (1 << kClearSamplers) |
4730  (1 << kClearTextures) |
4731  (1 << kClearVertexArray));
4732  return flags;
4733 }
4734 
4736  static const Flags flags((1 << Renderer::kProcessInfoRequests) |
4738  return flags;
4739 }
4740 
4742  static const Flags flags((1 << kRestoreActiveTexture) |
4743  (1 << kRestoreArrayBuffer) |
4745  (1 << kRestoreFramebuffer) |
4746  (1 << kRestoreShaderProgram) |
4747  (1 << kRestoreStateTable) |
4748  (1 << kRestoreVertexArray));
4749  return flags;
4750 }
4751 
4753  static const Flags flags((1 << kSaveActiveTexture) |
4754  (1 << kSaveArrayBuffer) |
4755  (1 << kSaveElementArrayBuffer) |
4756  (1 << kSaveFramebuffer) |
4757  (1 << kSaveShaderProgram) |
4758  (1 << kSaveStateTable) |
4759  (1 << kSaveVertexArray));
4760  return flags;
4761 }
4762 
4764  return resource_manager_->GetGraphicsManager();
4765 }
4766 
4768  return resource_manager_.get();
4769 }
4770 
4771 Renderer::ResourceBinderMap& Renderer::GetResourceBinderMap() {
4773  ResourceBinderMap, binders,
4774  new ResourceBinderMap(
4776  base::kLongTerm)));
4777  return *binders;
4778 }
4779 
4781  if (visual) {
4782  const size_t id = visual->GetId();
4783  ResourceBinderMap& binders = GetResourceBinderMap();
4784  base::WriteLock write_lock(GetResourceBinderLock());
4785  base::WriteGuard write_guard(&write_lock);
4786  binders.erase(id);
4787  }
4788 }
4789 
4791  const size_t id = portgfx::Visual::GetCurrentId();
4792  ResourceBinderMap& binders = GetResourceBinderMap();
4793  base::WriteLock write_lock(GetResourceBinderLock());
4794  base::WriteGuard write_guard(&write_lock);
4795  binders.erase(id);
4796 }
4797 
4798 Renderer::ResourceBinder* Renderer::GetInternalResourceBinder(
4799  size_t* visual_id) const {
4800  base::ReadLock read_lock(GetResourceBinderLock());
4801  base::ReadGuard read_guard(&read_lock);
4802  *visual_id = portgfx::Visual::GetCurrentId();
4803  ResourceBinderMap& binders = GetResourceBinderMap();
4804  ResourceBinderMap::iterator it = binders.find(*visual_id);
4805 
4806  if (it == binders.end())
4807  return nullptr;
4808 
4809  ResourceBinder* rb = it->second.get();
4810  DCHECK(rb);
4811  rb->SetResourceManager(resource_manager_.get());
4812  return rb;
4813 }
4814 
4815 Renderer::ResourceBinder*
4816 Renderer::GetOrCreateInternalResourceBinder(int line) const {
4817  size_t visual_id = 0;
4818  ResourceBinder* rb = GetInternalResourceBinder(&visual_id);
4819  if (visual_id == 0) {
4820  LOG(WARNING) << "***ION: renderer.cc:" << line
4821  << ": No Visual ID (invalid GL Context?)";
4822  DCHECK(!rb) << "Unexpected ResourceBinder for visual 0.";
4823  return nullptr;
4824  }
4825  if (!rb) {
4826  ResourceBinderMap& binders = GetResourceBinderMap();
4827  rb = new(GetAllocator()) ResourceBinder(GetGraphicsManager());
4828  base::WriteLock write_lock(GetResourceBinderLock());
4829  base::WriteGuard write_guard(&write_lock);
4830  DCHECK(binders.find(visual_id) == binders.end())
4831  << "Two threads tried to create ResourceBinders for the same Visual!";
4832  binders[visual_id].reset(rb);
4833  }
4834  DCHECK(rb);
4835  rb->SetResourceManager(resource_manager_.get());
4836  return rb;
4837 }
4838 
4840  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4841 
4842  if (resource_binder) {
4843  resource_binder->ClearNonFramebufferCachedBindings();
4844  if (!fbo.Get() || fbo->GetWidth() == 0 || fbo->GetHeight() == 0) {
4845  resource_binder->BindFramebuffer(
4846  *resource_binder->GetSavedId(kSaveFramebuffer), nullptr);
4847  } else {
4848  FramebufferResource* fbr =
4849  resource_manager_->GetResource(fbo.Get(), resource_binder);
4850  DCHECK(fbr);
4851  fbr->Bind(resource_binder);
4852  }
4853  resource_binder->SetCurrentFramebuffer(fbo);
4854  }
4855 }
4856 
4858  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4859  return resource_binder ?
4860  resource_binder->GetCurrentFramebuffer() : FramebufferObjectPtr();
4861 }
4862 
4864  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4865  if (resource_binder)
4866  resource_binder->UpdateDefaultFramebufferFromOpenGL();
4867 }
4868 
4870  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4871  if (resource_binder) {
4872  resource_binder->ClearNonFramebufferCachedBindings();
4873  resource_binder->ClearFramebufferBinding(0U);
4874  }
4875 }
4876 
4877 template <typename T>
4878 ION_API void Renderer::BindResource(T* holder) {
4879  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4880  if (resource_binder)
4881  resource_binder->BindResource(holder);
4882 }
4883 
4885 template ION_API void Renderer::BindResource<BufferObject>(
4886  BufferObject*); // NOLINT
4887 template ION_API void Renderer::BindResource<CubeMapTexture>(
4888  CubeMapTexture*); // NOLINT
4889 template ION_API void Renderer::BindResource<FramebufferObject>(
4890  FramebufferObject*); // NOLINT
4891 template ION_API void Renderer::BindResource<IndexBuffer>(
4892  IndexBuffer*); // NOLINT
4893 template ION_API void Renderer::BindResource<Sampler>(Sampler*); // NOLINT
4894 template ION_API void Renderer::BindResource<ShaderProgram>(
4895  ShaderProgram*); // NOLINT
4896 template ION_API void Renderer::BindResource<Texture>(Texture*); // NOLINT
4897 
4898 template <typename T>
4899 ION_API void Renderer::CreateOrUpdateResource(T* holder) {
4900  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4901  if (resource_binder)
4902  resource_binder->Process<ResourceBinder::CreateOrUpdateOp>(holder, 0U);
4903 }
4904 
4906 template ION_API void Renderer::CreateOrUpdateResource<AttributeArray>(
4907  AttributeArray*); // NOLINT
4908 template ION_API void Renderer::CreateOrUpdateResource<BufferObject>(
4909  BufferObject*); // NOLINT
4910 template ION_API void Renderer::CreateOrUpdateResource<CubeMapTexture>(
4911  CubeMapTexture*); // NOLINT
4912 template ION_API void Renderer::CreateOrUpdateResource<FramebufferObject>(
4913  FramebufferObject*); // NOLINT
4914 template ION_API void Renderer::CreateOrUpdateResource<IndexBuffer>(
4915  IndexBuffer*); // NOLINT
4916 template ION_API void Renderer::CreateOrUpdateResource<Sampler>(
4917  Sampler*); // NOLINT
4918 template ION_API void Renderer::CreateOrUpdateResource<ShaderInputRegistry>(
4919  ShaderInputRegistry*); // NOLINT
4920 template ION_API void Renderer::CreateOrUpdateResource<ShaderProgram>(
4921  ShaderProgram*); // NOLINT
4922 template ION_API void Renderer::CreateOrUpdateResource<Texture>(
4923  Texture*); // NOLINT
4924 
4925 void Renderer::ProcessStateTable(const StateTablePtr& state_table) {
4926  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4927  if (resource_binder)
4928  resource_binder->ProcessStateTable(state_table);
4929 }
4930 
4931 template <>
4932 ION_API void Renderer::CreateResourceWithExternallyManagedId<BufferObject>(
4933  BufferObject* holder, uint32 gl_id) {
4934  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4935  if (resource_binder && resource_binder->GetGraphicsManager()->IsBuffer(gl_id))
4936  resource_binder->Process<ResourceBinder::CreateOrUpdateOp>(holder, gl_id);
4937 }
4938 
4939 template <>
4940 ION_API void Renderer::CreateResourceWithExternallyManagedId<IndexBuffer>(
4941  IndexBuffer* holder, uint32 gl_id) {
4942  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4943  if (resource_binder && resource_binder->GetGraphicsManager()->IsBuffer(gl_id))
4944  resource_binder->Process<ResourceBinder::CreateOrUpdateOp>(holder, gl_id);
4945 }
4946 
4947 template <>
4948 ION_API void Renderer::CreateResourceWithExternallyManagedId<Texture>(
4949  Texture* holder, uint32 gl_id) {
4950  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4951  if (resource_binder &&
4952  resource_binder->GetGraphicsManager()->IsTexture(gl_id))
4953  resource_binder->Process<ResourceBinder::CreateOrUpdateOp>(holder, gl_id);
4954 }
4955 
4956 template <>
4957 ION_API void Renderer::CreateResourceWithExternallyManagedId<CubeMapTexture>(
4958  CubeMapTexture* holder, uint32 gl_id) {
4959  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4960  if (resource_binder &&
4961  resource_binder->GetGraphicsManager()->IsTexture(gl_id))
4962  resource_binder->Process<ResourceBinder::CreateOrUpdateOp>(holder, gl_id);
4963 }
4964 
4966  if (!node.Get() || !node->IsEnabled())
4967  return;
4968 
4969  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
4970  if (resource_binder)
4971  resource_binder->Traverse<ResourceBinder::CreateOrUpdateOp>(node,
4972  default_shader_.Get());
4973 }
4974 
4975 template <typename Operation>
4976 void Renderer::ResourceBinder::Traverse(const NodePtr& node,
4977  ShaderProgram* default_shader) {
4981  ShaderProgram* saved_current_program = current_shader_program_;
4982  ShaderProgramResource* saved_active_resource = active_shader_resource_;
4983  current_shader_program_ = default_shader;
4984 
4985  Visit<Operation>(node);
4986 
4987  current_shader_program_ = saved_current_program;
4988  active_shader_resource_ = saved_active_resource;
4989 }
4990 
4991 template <typename Operation>
4992 void Renderer::ResourceBinder::Visit(const NodePtr& node) {
4993  if (!node.Get() || !node->IsEnabled())
4994  return;
4995 
4997  if (ShaderProgram* shader = node->GetShaderProgram().Get()) {
4998  Process<Operation>(shader, 0U);
4999  current_shader_program_ = shader;
5000  }
5001 
5002  active_shader_resource_ = resource_manager_->GetResource(
5003  current_shader_program_, this);
5004 
5006  const base::AllocVector<Uniform>& uniforms = node->GetUniforms();
5007  const size_t num_uniforms = uniforms.size();
5008  for (size_t i = 0; i < num_uniforms; ++i) {
5009  Process<Operation>(&uniforms[i].GetRegistry(), 0U);
5010  if (uniforms[i].GetType() == kTextureUniform)
5011  Process<Operation>(uniforms[i].GetValue<TexturePtr>().Get(), 0U);
5012  else if (uniforms[i].GetType() == kCubeMapTextureUniform)
5013  Process<Operation>(uniforms[i].GetValue<CubeMapTexturePtr>().Get(), 0U);
5014  }
5015 
5017  const base::AllocVector<UniformBlockPtr>& uniform_blocks =
5018  node->GetUniformBlocks();
5019  const size_t num_uniform_blocks = uniform_blocks.size();
5020  for (size_t i = 0; i < num_uniform_blocks; ++i) {
5021  if (uniform_blocks[i]->IsEnabled()) {
5022  const base::AllocVector<Uniform>& uniforms =
5023  uniform_blocks[i]->GetUniforms();
5024  const size_t num_uniforms = uniforms.size();
5025  for (size_t i = 0; i < num_uniforms; ++i) {
5026  Process<Operation>(&uniforms[i].GetRegistry(), 0U);
5027  if (uniforms[i].GetType() == kTextureUniform)
5028  Process<Operation>(uniforms[i].GetValue<TexturePtr>().Get(), 0U);
5029  else if (uniforms[i].GetType() == kCubeMapTextureUniform)
5030  Process<Operation>(
5031  uniforms[i].GetValue<CubeMapTexturePtr>().Get(), 0U);
5032  }
5033  }
5034  }
5035 
5037  const base::AllocVector<ShapePtr>& shapes = node->GetShapes();
5038  const size_t num_shapes = shapes.size();
5039  for (size_t i = 0; i < num_shapes; ++i)
5040  VisitShape<Operation>(shapes[i]);
5041 
5042  ShaderProgram* saved_program = current_shader_program_;
5043 
5045  const base::AllocVector<NodePtr>& children = node->GetChildren();
5046  const size_t num_children = children.size();
5047  for (size_t i = 0; i < num_children; ++i) {
5048  Visit<Operation>(children[i]);
5049  current_shader_program_ = saved_program;
5050  }
5051 }
5052 
5053 template <typename Operation>
5054 void Renderer::ResourceBinder::VisitShape(const ShapePtr& shape) {
5055  Process<Operation>(shape->GetIndexBuffer().Get(), 0U);
5056  Process<Operation>(shape->GetAttributeArray().Get(), 0U);
5057 }
5058 
5060  if (shape.Get()) {
5061  ResourceBinder* resource_binder =
5062  GetOrCreateInternalResourceBinder(__LINE__);
5063  if (resource_binder)
5064  resource_binder->VisitShape<ResourceBinder::CreateOrUpdateOp>(shape);
5065  }
5066 }
5067 
5068 template <typename T>
5069 ION_API void Renderer::RequestForcedUpdate(T* holder) {
5070  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5071  if (resource_binder)
5072  resource_binder->Process<ResourceBinder::RequestUpdateOp>(holder, 0U);
5073 }
5074 
5076 template ION_API void Renderer::RequestForcedUpdate<AttributeArray>(
5077  AttributeArray*); // NOLINT
5078 template ION_API void Renderer::RequestForcedUpdate<BufferObject>(
5079  BufferObject*); // NOLINT
5080 template ION_API void Renderer::RequestForcedUpdate<CubeMapTexture>(
5081  CubeMapTexture*); // NOLINT
5082 template ION_API void Renderer::RequestForcedUpdate<FramebufferObject>(
5083  FramebufferObject*); // NOLINT
5084 template ION_API void Renderer::RequestForcedUpdate<IndexBuffer>(
5085  IndexBuffer*); // NOLINT
5086 template ION_API void Renderer::RequestForcedUpdate<Sampler>(
5087  Sampler*); // NOLINT
5088 template ION_API void Renderer::RequestForcedUpdate<ShaderProgram>(
5089  ShaderProgram*); // NOLINT
5090 template ION_API void Renderer::RequestForcedUpdate<ShaderInputRegistry>(
5091  ShaderInputRegistry*); // NOLINT
5092 template ION_API void Renderer::RequestForcedUpdate<Texture>(
5093  Texture*); // NOLINT
5094 
5096  if (!node.Get() || !node->IsEnabled())
5097  return;
5098 
5099  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5100  if (resource_binder)
5101  resource_binder->Traverse<ResourceBinder::RequestUpdateOp>(node,
5102  default_shader_.Get());
5103 }
5104 
5106  if (shape.Get()) {
5107  ResourceBinder* resource_binder =
5108  GetOrCreateInternalResourceBinder(__LINE__);
5109  if (resource_binder) {
5110  resource_binder->VisitShape<ResourceBinder::RequestUpdateOp>(shape);
5111  }
5112  }
5113 }
5114 
5115 void Renderer::ResourceBinder::ProcessStateTable(
5116  const StateTablePtr& state_table) {
5117  if (const StateTable* st = state_table.Get()) {
5118  GraphicsManager* gm = GetGraphicsManager().Get();
5119 
5121  client_state_table_->MergeValuesFrom(*st, *st);
5122  ClearFromStateTable(*st, gl_state_table_.Get(), gm);
5123  UpdateFromStateTable(*st, gl_state_table_.Get(), gm);
5125  gl_state_table_->MergeNonClearValuesFrom(*st, *st);
5126  }
5127 }
5128 
5130  if (u.IsValid()) {
5131  ResourceBinder* resource_binder =
5132  GetOrCreateInternalResourceBinder(__LINE__);
5133  if (resource_binder) {
5134  ShaderInputRegistryResource* sirr = resource_manager_->GetResource(
5135  &u.GetRegistry(), resource_binder);
5136  sirr->Update(resource_binder);
5137  sirr->SetInitialValue(u);
5138  }
5139  }
5140 }
5141 
5143  const FramebufferObjectPtr& ms_fbo, const FramebufferObjectPtr& dest_fbo) {
5144  const GraphicsManagerPtr& gm = GetGraphicsManager();
5145 
5147  if (!gm->IsFunctionGroupAvailable(GraphicsManager::kFramebufferBlit) &&
5148  !gm->IsFunctionGroupAvailable(
5150  LOG(WARNING) << "No multisampled frambuffer functions available.";
5151  return;
5152  }
5153 
5155  GLuint ms_fbo_id = GetResourceGlId(ms_fbo.Get());
5156  GLuint dest_fbo_id = GetResourceGlId(dest_fbo.Get());
5157 
5159  const FramebufferObjectPtr previous_fbo = GetCurrentFramebuffer();
5160 
5162  gm->BindFramebuffer(GL_READ_FRAMEBUFFER, ms_fbo_id);
5163  gm->BindFramebuffer(GL_DRAW_FRAMEBUFFER, dest_fbo_id);
5164 
5166  if (gm->IsFunctionGroupAvailable(GraphicsManager::kFramebufferBlit)) {
5167  gm->BlitFramebuffer(0, 0, ms_fbo->GetWidth(), ms_fbo->GetHeight(), 0, 0,
5168  dest_fbo->GetWidth(), dest_fbo->GetHeight(),
5169  GL_COLOR_BUFFER_BIT, GL_NEAREST);
5170  } else if (gm->IsFunctionGroupAvailable(
5172  gm->ResolveMultisampleFramebuffer();
5173  }
5174 
5176  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5177  resource_binder->ClearFramebufferBinding(0);
5178  BindFramebuffer(previous_fbo);
5179 }
5180 
5181 void Renderer::DrawScene(const NodePtr& node) {
5182  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5183  if (resource_binder) {
5184  resource_binder->DrawScene(node, flags_, default_shader_.Get());
5186  if (flags_.test(kProcessInfoRequests))
5187  resource_manager_->ProcessResourceInfoRequests(resource_binder);
5188  }
5189 }
5190 
5191 void Renderer::ResourceBinder::MarkAttachmentImplicitlyChanged(
5192  const FramebufferObject::Attachment& attachment) {
5193  if (Texture* tex = attachment.GetTexture().Get()) {
5194  Renderer::SetResourceHolderBit(tex, Texture::kContentsImplicitlyChanged);
5195  }
5196  if (CubeMapTexture* tex = attachment.GetCubeMapTexture().Get()) {
5197  Renderer::SetResourceHolderBit(tex,
5199  }
5200 }
5201 
5202 void Renderer::ResourceBinder::MapBufferObjectDataRange(
5203  const BufferObjectPtr& buffer,
5204  BufferObjectDataMapMode mode,
5205  const math::Range1ui& range_in) {
5206  BufferObject* bo = buffer.Get();
5207  if (!bo)
5208  return;
5209  if (bo->GetMappedPointer()) {
5210  LOG(WARNING) << "A buffer that is already mapped was passed to"
5212  return;
5213  }
5214  if (range_in.IsEmpty()) {
5215  LOG(WARNING) << "Ignoring empty range passed to"
5216  << ION_PRETTY_FUNCTION << ", nothing will be mapped";
5217  return;
5218  }
5219  const Range1ui entire_range(
5220  0U, static_cast<uint32>(bo->GetStructSize() * bo->GetCount()));
5221  Range1ui range = range_in;
5222  void* data = nullptr;
5223  BufferObject::MappedBufferData::DataSource data_source =
5224  BufferObject::MappedBufferData::kGpuMapped;
5225  GraphicsManager* gm = GetGraphicsManager().Get();
5227  if (gm->IsFunctionGroupAvailable(GraphicsManager::kMapBufferRange)) {
5228  BufferResource* br = resource_manager_->GetResource(bo, this);
5229  br->Bind(this);
5230  GLenum access_mode;
5231  if (mode == kReadOnly)
5232  access_mode = GL_MAP_READ_BIT;
5233  else if (mode == kWriteOnly)
5234  access_mode = GL_MAP_WRITE_BIT;
5235  else
5236  access_mode = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
5237  data = gm->MapBufferRange(br->GetGlTarget(), range.GetMinPoint(),
5238  range.GetSize(), access_mode);
5239  } else if (gm->IsFunctionGroupAvailable(GraphicsManager::kMapBuffer) &&
5240  range == entire_range) {
5241  BufferResource* br = resource_manager_->GetResource(bo, this);
5242  br->Bind(this);
5243  GLenum access_mode;
5244  if (mode == kReadOnly)
5245  access_mode = GL_READ_ONLY;
5246  else if (mode == kWriteOnly)
5247  access_mode = GL_WRITE_ONLY;
5248  else
5249  access_mode = GL_READ_WRITE;
5250  data = gm->MapBuffer(br->GetGlTarget(), access_mode);
5251  } else if (range.GetSize() <= entire_range.GetSize()) {
5253  if (bo->GetData().Get() && bo->GetData()->GetData() &&
5254  bo->GetCount() * bo->GetStructSize() >= range_in.GetMaxPoint()) {
5255  data = static_cast<void*>(
5256  bo->GetData()->GetMutableData<uint8>() + range_in.GetMinPoint());
5257  data_source = BufferObject::MappedBufferData::kDataContainer;
5258  } else {
5259  data = bo->GetAllocator()->AllocateMemory(range.GetSize());
5260  data_source = BufferObject::MappedBufferData::kAllocated;
5261  if (mode != kWriteOnly) {
5262  LOG(WARNING) << "MapBufferObjectDataRange() glMapBufferRange not "
5263  "supported and BufferObject's DataContainer has been wiped so "
5264  "mapped bytes are uninitialized, i.e., garbage.";
5265  }
5266  }
5267  }
5268  if (data)
5269  bo->SetMappedData(range, data, data_source, mode == kReadOnly);
5270  else
5271  LOG(ERROR) << "Failed to allocate data for "
5273 }
5274 
5275 void Renderer::ResourceBinder::UnmapBufferObjectData(
5276  const BufferObjectPtr& buffer) {
5277  BufferObject* bo = buffer.Get();
5278  if (!bo)
5279  return;
5280  if (void* ptr = bo->GetMappedPointer()) {
5281  BufferResource* br = resource_manager_->GetResource(bo, this);
5282  br->Bind(this);
5283  if (bo->GetMappedData().data_source ==
5284  BufferObject::MappedBufferData::kGpuMapped &&
5285  graphics_manager_->IsFunctionGroupAvailable(
5287  graphics_manager_->UnmapBuffer(br->GetGlTarget());
5288  } else {
5289  if (!bo->GetMappedData().read_only)
5290  br->UploadSubData(bo->GetMappedData().range, ptr);
5291  if (bo->GetMappedData().data_source ==
5292  BufferObject::MappedBufferData::kAllocated) {
5294  bo->GetAllocator()->DeallocateMemory(ptr);
5295  }
5296  }
5298  bo->SetMappedData(
5299  Range1ui(),
5300  nullptr,
5301  base::InvalidEnumValue<BufferObject::MappedBufferData::DataSource>(),
5302  true);
5303  } else {
5304  LOG(WARNING) << "An unmapped BufferObject was passed to"
5306  }
5307 }
5308 
5309 void Renderer::ResourceBinder::DrawScene(const NodePtr& node,
5310  const Flags& flags,
5311  ShaderProgram* default_shader) {
5312  GraphicsManager* gm = GetGraphicsManager().Get();
5313  DCHECK(gm);
5314 
5315  if ((flags & AllSaveFlags()).any()) {
5317  if (flags.test(kSaveActiveTexture))
5318  gm->GetIntegerv(GL_ACTIVE_TEXTURE, GetSavedId(kSaveActiveTexture));
5319  if (flags.test(kSaveArrayBuffer))
5320  gm->GetIntegerv(GL_ARRAY_BUFFER_BINDING, GetSavedId(kSaveArrayBuffer));
5321  if (flags.test(kSaveElementArrayBuffer))
5322  gm->GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,
5323  GetSavedId(kSaveElementArrayBuffer));
5324  if (flags.test(kSaveFramebuffer))
5325  gm->GetIntegerv(GL_FRAMEBUFFER_BINDING, GetSavedId(kSaveFramebuffer));
5326  if (flags.test(kSaveStateTable)) {
5327  UpdateStateTable(0, 0, gm, saved_state_table_.Get());
5329  const base::IndexMap<StateTable::Capability, GLenum> capability_map =
5330  base::EnumHelper::GetIndexMap<StateTable::Capability>();
5331  const size_t num_capabilities = capability_map.GetCount();
5332  for (size_t i = 0; i < num_capabilities; ++i) {
5333  const StateTable::Capability st_cap =
5334  static_cast<StateTable::Capability>(i);
5336  if (!saved_state_table_->IsCapabilitySet(st_cap))
5337  saved_state_table_->Enable(st_cap, st_cap == StateTable::kDither);
5338  }
5339  }
5340  if (flags.test(kSaveShaderProgram))
5341  gm->GetIntegerv(GL_CURRENT_PROGRAM, GetSavedId(kSaveShaderProgram));
5342  if (flags.test(kSaveVertexArray) &&
5343  gm->IsFunctionGroupAvailable(GraphicsManager::kVertexArrays))
5344  gm->GetIntegerv(GL_VERTEX_ARRAY_BINDING, GetSavedId(kSaveVertexArray));
5345  }
5346 
5348  if (FramebufferResource* fbr = GetActiveFramebuffer()) fbr->Bind(this);
5349 
5351  if (flags.test(kProcessReleases)) resource_manager_->ReleaseAll(this);
5352 
5355  current_shader_program_ = default_shader;
5356 
5358  current_traversal_index_ = 0;
5359  if (node.Get()) {
5360  DrawNode(*node, gm);
5364  if (FramebufferObject* fbo = GetCurrentFramebuffer().Get()) {
5365  MarkAttachmentImplicitlyChanged(fbo->GetColorAttachment(0U));
5366  MarkAttachmentImplicitlyChanged(fbo->GetDepthAttachment());
5367  MarkAttachmentImplicitlyChanged(fbo->GetStencilAttachment());
5368  }
5369  }
5370 
5372  if ((flags & (AllRestoreFlags() | AllClearFlags())).any()) {
5374  if (flags.test(kRestoreArrayBuffer))
5375  BindBuffer(BufferObject::kArrayBuffer, *GetSavedId(kSaveArrayBuffer),
5376  nullptr);
5377  else if (flags.test(kClearArrayBuffer))
5378  BindBuffer(BufferObject::kArrayBuffer, 0U, nullptr);
5380  if (flags.test(kRestoreElementArrayBuffer))
5381  BindBuffer(BufferObject::kElementBuffer,
5382  *GetSavedId(kSaveElementArrayBuffer), nullptr);
5383  else if (flags.test(kClearElementArrayBuffer))
5384  BindBuffer(BufferObject::kElementBuffer, 0U, nullptr);
5386  if (flags.test(kRestoreFramebuffer)) {
5387  BindFramebuffer(*GetSavedId(kSaveFramebuffer), nullptr);
5388  SetCurrentFramebuffer(FramebufferObjectPtr());
5389  } else if (flags.test(kClearFramebuffer)) {
5390  BindFramebuffer(0U, nullptr);
5391  SetCurrentFramebuffer(FramebufferObjectPtr());
5392  }
5394  if (flags.test(kRestoreShaderProgram))
5395  BindProgram(*GetSavedId(kSaveShaderProgram), nullptr);
5396  else if (flags.test(kClearShaderProgram))
5397  BindProgram(0U, nullptr);
5399  if (flags.test(kRestoreStateTable)) {
5400  UpdateFromStateTable(*saved_state_table_, gl_state_table_.Get(), gm);
5401  gl_state_table_->MergeNonClearValuesFrom(*saved_state_table_,
5402  *saved_state_table_);
5403  }
5405  if (gm->IsFunctionGroupAvailable(GraphicsManager::kVertexArrays)) {
5406  if (flags.test(kRestoreVertexArray))
5407  BindVertexArray(*GetSavedId(kSaveVertexArray), nullptr);
5408  else if (flags.test(kClearVertexArray))
5409  BindVertexArray(0U, nullptr);
5410  }
5411 
5413  if (flags.test(kClearCubemaps)) {
5414  const GLuint count = static_cast<GLuint>(image_units_.size());
5415  for (GLuint i = 0; i < count; ++i) {
5416  ActivateUnit(i);
5417  gm->BindTexture(GL_TEXTURE_CUBE_MAP, 0);
5418  ClearTextureBinding(0U, i);
5419  if (gm->IsFunctionGroupAvailable(GraphicsManager::kTexture3d)) {
5420  gm->BindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
5421  ClearTextureBinding(0U, i);
5422  }
5423  }
5424  }
5425  if (flags.test(kClearTextures)) {
5426  const GLuint count = static_cast<GLuint>(image_units_.size());
5427  for (GLuint i = 0; i < count; ++i) {
5428  ActivateUnit(i);
5429  gm->BindTexture(GL_TEXTURE_2D, 0);
5430  ClearTextureBinding(0U, i);
5431  if (gm->IsFunctionGroupAvailable(GraphicsManager::kTexture3d)) {
5432  gm->BindTexture(GL_TEXTURE_1D_ARRAY, 0);
5433  gm->BindTexture(GL_TEXTURE_2D_ARRAY, 0);
5434  gm->BindTexture(GL_TEXTURE_3D, 0);
5435  }
5436  if (gm->IsExtensionSupported("image_external")) {
5437  gm->BindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
5438  }
5439  }
5440  }
5441  if (flags.test(kClearSamplers)) {
5442  const GLuint count = static_cast<GLuint>(image_units_.size());
5443  for (GLuint i = 0; i < count; ++i)
5444  BindSamplerToUnit(0U, i);
5445  }
5447  if (flags.test(kRestoreActiveTexture))
5448  ActivateUnit(*GetSavedId(kSaveActiveTexture) - GL_TEXTURE0);
5449  else if (flags.test(kClearActiveTexture))
5450  ActivateUnit(0U);
5451  }
5452 }
5453 
5455  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5456  if (resource_binder)
5457  resource_manager_->ProcessResourceInfoRequests(resource_binder);
5458 }
5459 
5460 void Renderer::UpdateStateFromOpenGL(int window_width, int window_height) {
5461  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5462  if (resource_binder)
5463  UpdateStateTable(window_width, window_height, GetGraphicsManager().Get(),
5464  resource_binder->GetStateTable());
5465 }
5466 
5468  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5469  if (resource_binder)
5470  resource_binder->GetStateTable()->CopyFrom(*state_table);
5471 }
5472 
5474  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5475  if (!resource_binder) {
5477  StateTablePtr, kDefaultStateTable, (new StateTablePtr(new StateTable)));
5478  LOG(WARNING) << "***ION: No ResourceBinder (invalid GL Context?): "
5479  << " using default StateTable";
5480  return *kDefaultStateTable->Get();
5481  }
5482  return *resource_binder->GetStateTable();
5483 }
5484 
5486  BufferObjectDataMapMode mode) {
5487  if (BufferObject* bo = buffer.Get()) {
5489  const Range1ui range(
5490  0U, static_cast<uint32>(bo->GetStructSize() * bo->GetCount()));
5491  MapBufferObjectDataRange(buffer, mode, range);
5492  } else {
5493  LOG(WARNING) << "A NULL BufferObject was passed to"
5495  }
5496 }
5497 
5500  const math::Range1ui& range_in) {
5501  if (buffer.Get()) {
5502  if (ResourceBinder* resource_binder =
5503  GetOrCreateInternalResourceBinder(__LINE__)) {
5504  resource_binder->MapBufferObjectDataRange(buffer, mode, range_in);
5505  }
5506  } else {
5507  LOG(WARNING) << "A NULL BufferObject was passed to"
5509  }
5510 }
5511 
5513  if (buffer.Get()) {
5514  if (ResourceBinder* resource_binder =
5515  GetOrCreateInternalResourceBinder(__LINE__)) {
5516  resource_binder->UnmapBufferObjectData(buffer);
5517  }
5518  } else {
5519  LOG(WARNING) << "A NULL BufferObject was passed to"
5521  }
5522 }
5523 
5525  Image::Format format,
5526  const base::AllocatorPtr& allocator) {
5527  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5528  return resource_binder ?
5529  resource_binder->ReadImage(range, format, allocator) : ImagePtr();
5530 }
5531 
5532 #if ION_PRODUCTION
5533 void Renderer::PushDebugMarker(const std::string& label) {}
5534 void Renderer::PopDebugMarker() {}
5535 #else
5536 void Renderer::PushDebugMarker(const std::string& marker) {
5537  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5538  if (resource_binder)
5539  resource_binder->GetStreamAnnotator()->Push(marker);
5540 }
5542  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5543  if (resource_binder)
5544  resource_binder->GetStreamAnnotator()->Pop();
5545 }
5546 #endif
5547 
5548 template <typename T>
5549 uint32 Renderer::GetResourceGlId(T* holder) {
5550  uint32 id = 0U;
5551  if (holder) {
5552  typedef typename HolderToResource<T>::ResourceType ResourceType;
5553  ResourceBinder* resource_binder =
5554  GetOrCreateInternalResourceBinder(__LINE__);
5555  if (resource_binder) {
5556  resource_binder->BindResource(holder);
5557  ResourceType* resource =
5558  resource_manager_->GetResource(holder, resource_binder);
5559  id = resource->GetId();
5560  }
5561  }
5562  return id;
5563 }
5564 
5566 template ION_API uint32
5567 Renderer::GetResourceGlId<BufferObject>(BufferObject*); // NOLINT
5568 template ION_API uint32
5569 Renderer::GetResourceGlId<CubeMapTexture>(CubeMapTexture*); // NOLINT
5570 template ION_API uint32
5571 Renderer::GetResourceGlId<FramebufferObject>(FramebufferObject*); // NOLINT
5572 template ION_API uint32
5573 Renderer::GetResourceGlId<IndexBuffer>(IndexBuffer*); // NOLINT
5574 template ION_API uint32 Renderer::GetResourceGlId<Sampler>(Sampler*); // NOLINT
5575 template ION_API uint32 Renderer::GetResourceGlId<Shader>(Shader*); // NOLINT
5576 template ION_API uint32
5577 Renderer::GetResourceGlId<ShaderProgram>(ShaderProgram*); // NOLINT
5578 template ION_API uint32 Renderer::GetResourceGlId<Texture>(Texture*); // NOLINT
5579 
5581  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5582  if (resource_binder)
5583  resource_binder->SetImageUnitRange(units);
5584 }
5585 
5586 template <typename T>
5587 void Renderer::ClearResources(const T* holder) {
5588  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5589  if (resource_binder)
5590  resource_manager_->ReleaseResources(holder, resource_binder);
5591 }
5592 
5594 template ION_API void Renderer::ClearResources<AttributeArray>(
5595  const AttributeArray*);
5596 template ION_API void Renderer::ClearResources<BufferObject>(
5597  const BufferObject*);
5598 template ION_API void Renderer::ClearResources<CubeMapTexture>(
5599  const CubeMapTexture*);
5600 template ION_API void Renderer::ClearResources<FramebufferObject>(
5601  const FramebufferObject*);
5602 template ION_API void Renderer::ClearResources<Sampler>(const Sampler*);
5603 template ION_API void Renderer::ClearResources<Shader>(const Shader*);
5604 template ION_API void Renderer::ClearResources<ShaderProgram>(
5605  const ShaderProgram*);
5606 template ION_API void Renderer::ClearResources<Texture>(const Texture*);
5607 
5609  for (int i = 0; i < kNumResourceTypes; ++i)
5610  resource_manager_->ReleaseTypedResources(static_cast<ResourceType>(i));
5611  ReleaseResources();
5612 }
5613 
5614 void Renderer::ClearTypedResources(ResourceType type) {
5615  resource_manager_->ReleaseTypedResources(type);
5616  ReleaseResources();
5617 }
5618 
5620  ResourceBinder* resource_binder = GetOrCreateInternalResourceBinder(__LINE__);
5621  if (resource_binder)
5622  resource_manager_->ReleaseAll(resource_binder);
5623 }
5624 
5625 size_t Renderer::GetGpuMemoryUsage(ResourceType type) const {
5626  return resource_manager_->GetGpuMemoryUsage(type);
5627 }
5628 
5629 const ShaderProgramPtr Renderer::CreateDefaultShaderProgram(
5630  const base::AllocatorPtr& allocator) {
5631  static const char* kDefaultVertexShaderString =
5632  "uniform mat4 uProjectionMatrix;\n"
5633  "uniform mat4 uModelviewMatrix;\n"
5634  "attribute vec3 aVertex;\n"
5635  "\n"
5636  "void main(void) {\n"
5637  " gl_Position = uProjectionMatrix * uModelviewMatrix *\n"
5638  " vec4(aVertex, 1.);\n"
5639  "}\n";
5640 
5641  static const char* kDefaultFragmentShaderString =
5642  "#ifdef GL_ES\n"
5643  "precision mediump float;\n"
5644  "#endif\n"
5645  "\n"
5646  "uniform vec4 uBaseColor;\n"
5647  "\n"
5648  "void main(void) {\n"
5649  " gl_FragColor = uBaseColor;\n"
5650  "}\n";
5651 
5654  ShaderInputRegistryPtr empty_registry(new(allocator) ShaderInputRegistry);
5655  empty_registry->IncludeGlobalRegistry();
5656 
5657  ShaderProgramPtr program(new(allocator) ShaderProgram(empty_registry));
5658  program->SetLabel("Default Renderer shader");
5659  program->SetVertexShader(
5660  ShaderPtr(new(allocator) Shader(kDefaultVertexShaderString)));
5661  program->SetFragmentShader(
5662  ShaderPtr(new(allocator) Shader(kDefaultFragmentShaderString)));
5663  program->GetVertexShader()->SetLabel("Default Renderer vertex shader");
5664  program->GetFragmentShader()->SetLabel("Default Renderer fragment shader");
5665  return program;
5666 }
5667 
5668 void Renderer::SetResourceHolderBit(const ResourceHolder* holder, int bit) {
5669  holder->OnChanged(bit);
5670 }
5671 
5672 void Renderer::ResourceBinder::DrawNode(const Node& node, GraphicsManager* gm) {
5673  if (!node.IsEnabled())
5674  return;
5675 
5676  ScopedLabel label(this, &node, node.GetLabel());
5677 
5678  if (const StateTable* st = node.GetStateTable().Get()) {
5681  traversal_state_tables_[current_traversal_index_]->CopyFrom(
5682  *client_state_table_.Get());
5684  if (++current_traversal_index_ >= traversal_state_tables_.size())
5685  traversal_state_tables_.push_back(StateTablePtr(new StateTable));
5686 
5688  client_state_table_->MergeValuesFrom(*st, *st);
5689  ClearFromStateTable(*st, gl_state_table_.Get(), gm);
5690  if (st->AreSettingsEnforced()) {
5691  UpdateFromStateTable(*st, gl_state_table_.Get(), gm);
5693  gl_state_table_->MergeNonClearValuesFrom(*st, *st);
5694  }
5695  }
5696 
5698  if (ShaderProgram* shader = node.GetShaderProgram().Get())
5699  current_shader_program_ = shader;
5700  DCHECK(current_shader_program_);
5701 
5703  PushUniforms(&node, node.GetUniforms());
5704  const base::AllocVector<UniformBlockPtr>& uniform_blocks =
5705  node.GetUniformBlocks();
5706  const size_t num_uniform_blocks = uniform_blocks.size();
5707  for (size_t i = 0; i < num_uniform_blocks; ++i)
5708  if (uniform_blocks[i]->IsEnabled())
5709  PushUniforms(&node, uniform_blocks[i]->GetUniforms());
5710 
5712  const base::AllocVector<ShapePtr>& shapes = node.GetShapes();
5713  if (const size_t num_shapes = shapes.size()) {
5715  UpdateFromStateTable(*client_state_table_, gl_state_table_.Get(), gm);
5716 
5719  resource_manager_->GetResource(current_shader_program_, this)->Bind(this);
5720 
5722  for (size_t i = 0; i < num_shapes; ++i)
5723  DrawShape(*shapes[i], gm);
5724 
5726  gl_state_table_->MergeNonClearValuesFrom(*client_state_table_,
5727  *client_state_table_);
5728  }
5729 
5732  ShaderProgram* saved_shader_program = current_shader_program_;
5733 
5735  const base::AllocVector<NodePtr>& children = node.GetChildren();
5736  const size_t num_children = children.size();
5737  for (size_t i = 0; i < num_children; ++i) {
5738  DrawNode(*children[i], gm);
5740  current_shader_program_ = saved_shader_program;
5741  }
5742 
5744  if (const StateTable* st = node.GetStateTable().Get()) {
5745  --current_traversal_index_;
5746  client_state_table_->MergeNonClearValuesFrom(
5747  *traversal_state_tables_[current_traversal_index_].Get(), *st);
5748  }
5749 
5751  PopUniforms(node.GetUniforms());
5752  for (size_t i = 0; i < num_uniform_blocks; ++i)
5753  if (uniform_blocks[i]->IsEnabled())
5754  PopUniforms(uniform_blocks[i]->GetUniforms());
5755 }
5756 
5757 void Renderer::ResourceBinder::DrawShape(const Shape& shape,
5758  GraphicsManager* gm) {
5759  if (!shape.GetAttributeArray().Get())
5760  return;
5761  const AttributeArray& attribute_array = *shape.GetAttributeArray();
5762  if (attribute_array.GetAttributeCount() == 0U ||
5763  (shape.GetIndexBuffer().Get() && !shape.GetIndexBuffer()->GetCount()))
5764  return;
5765 
5766  ScopedLabel label(this, &shape, shape.GetLabel());
5767 
5771  VertexArrayResource* var;
5772  if (gm->IsFunctionGroupAvailable(GraphicsManager::kVertexArrays))
5773  var = resource_manager_->GetResource(&attribute_array, this);
5774  else
5775  var = resource_manager_->GetResource(
5776  reinterpret_cast<const AttributeArrayEmulator*>(&attribute_array),
5777  this);
5778  DCHECK(var);
5779  if (var && !var->BindAndCheckBuffers(false, this))
5780  return;
5781 
5783  if (IndexBuffer* ib = shape.GetIndexBuffer().Get()) {
5784  DrawIndexedShape(shape, *ib, gm);
5785  } else {
5786  DrawNonindexedShape(shape, var->GetVertexCount(), gm);
5787  }
5788 }
5789 
5790 void Renderer::ResourceBinder::DrawIndexedShape(const Shape& shape,
5791  const IndexBuffer& ib,
5792  GraphicsManager* gm) {
5794  BufferResource* br = resource_manager_->GetResource(&ib, this);
5795  DCHECK(br);
5796  br->Bind(this);
5797 
5801  const BufferObject::Spec& spec = ib.GetSpec(0);
5803  const GLenum data_type = base::EnumHelper::GetConstant(spec.type);
5804  if (gm->GetGlApiStandard() == GraphicsManager::kEs &&
5805  gm->GetGlVersion() < 30 &&
5806  (data_type == GL_INT || data_type == GL_UNSIGNED_INT)) {
5807  LOG(ERROR) << "***ION: Unable to draw shape " << shape.GetLabel()
5808  << " using index buffer: "
5809  << "The component type is not supported on this platform";
5810  }
5811  const GLenum prim_type =
5812  base::EnumHelper::GetConstant(shape.GetPrimitiveType());
5813  if (const size_t range_count = shape.GetVertexRangeCount()) {
5815  for (size_t i = 0; i < range_count; ++i) {
5816  if (shape.IsVertexRangeEnabled(i)) {
5817  const Range1i& range = shape.GetVertexRange(i);
5818  const int start_index = range.GetMinPoint()[0];
5819  const int count = range.GetSize();
5820  DCHECK_GT(count, 0);
5821  const int instance_count = shape.GetVertexRangeInstanceCount(i);
5823  if (instance_count &&
5824  gm->IsFunctionGroupAvailable(
5826  gm->DrawElementsInstanced(prim_type, count, data_type,
5827  reinterpret_cast<const GLvoid*>(
5828  start_index * ib.GetStructSize()),
5829  instance_count);
5830  } else {
5831  if (instance_count) {
5832  LOG_ONCE(WARNING) << "***ION: Instanced drawing is not "
5833  "available. The vertex ranges in Shape: "
5834  << shape.GetLabel()
5835  << " will be drawn only once.";
5836  }
5837  gm->DrawElements(prim_type, count, data_type,
5838  reinterpret_cast<const GLvoid*>(
5839  start_index * ib.GetStructSize()));
5840  }
5841  }
5842  }
5843  } else {
5845  const int instance_count = shape.GetInstanceCount();
5846  if (instance_count &&
5847  gm->IsFunctionGroupAvailable(GraphicsManager::kInstancedDrawing)) {
5848  gm->DrawElementsInstanced(
5849  prim_type, static_cast<GLsizei>(ib.GetCount()), data_type,
5850  reinterpret_cast<const GLvoid*>(0), instance_count);
5851  } else {
5852  if (instance_count) {
5853  LOG_ONCE(WARNING)
5854  << "***ION: Instanced drawing is not available. Shape: "
5855  << shape.GetLabel() << " will be drawn only once.";
5856  }
5857  gm->DrawElements(prim_type, static_cast<GLsizei>(ib.GetCount()),
5858  data_type, reinterpret_cast<const GLvoid*>(0));
5859  }
5860  }
5861 }
5862 
5863 void Renderer::ResourceBinder::DrawNonindexedShape(const Shape& shape,
5864  size_t vertex_count,
5865  GraphicsManager* gm) {
5866  const GLenum prim_type =
5867  base::EnumHelper::GetConstant(shape.GetPrimitiveType());
5868  if (const size_t range_count = shape.GetVertexRangeCount()) {
5870  for (size_t i = 0; i < range_count; ++i) {
5871  if (shape.IsVertexRangeEnabled(i)) {
5872  const Range1i& range = shape.GetVertexRange(i);
5873  const int start_index = range.GetMinPoint()[0];
5874  const int count = range.GetSize();
5875  DCHECK_GT(count, 0);
5876  const int instance_count = shape.GetVertexRangeInstanceCount(i);
5877  if (instance_count &&
5878  gm->IsFunctionGroupAvailable(GraphicsManager::kInstancedDrawing)) {
5879  gm->DrawArraysInstanced(prim_type, start_index, count,
5880  instance_count);
5881  } else {
5882  if (instance_count) {
5883  LOG_ONCE(WARNING) << "***ION: Instanced drawing is not available. "
5884  "The vertex ranges in Shape: "
5885  << shape.GetLabel()
5886  << " will be drawn only once.";
5887  }
5888  gm->DrawArrays(prim_type, start_index, count);
5889  }
5890  }
5891  }
5892  } else {
5894  const int instance_count = shape.GetInstanceCount();
5895  if (instance_count &&
5896  gm->IsFunctionGroupAvailable(GraphicsManager::kInstancedDrawing)) {
5897  gm->DrawArraysInstanced(prim_type, 0, static_cast<GLsizei>(vertex_count),
5898  instance_count);
5899  } else {
5900  if (instance_count) {
5901  LOG_ONCE(WARNING)
5902  << "***ION: Instanced drawing is not available. Shape: "
5903  << shape.GetLabel() << " will be drawn only once.";
5904  }
5905  gm->DrawArrays(prim_type, 0, static_cast<GLsizei>(vertex_count));
5906  }
5907  }
5908 }
5909 
5910 void Renderer::ResourceBinder::BindBuffer(BufferObject::Target target,
5911  GLuint id, BufferResource* resource) {
5912  if (id != active_buffers_[target].buffer) {
5913  active_buffers_[target].buffer = id;
5914  active_buffers_[target].resource = resource;
5915  GetGraphicsManager()->BindBuffer(base::EnumHelper::GetConstant(target), id);
5916  if (target == BufferObject::kElementBuffer && active_vertex_array_resource_)
5917  active_vertex_array_resource_->SetElementArrayBinding(id, resource);
5918  }
5919 }
5920 
5921 void Renderer::ResourceBinder::BindFramebuffer(GLuint id,
5922  FramebufferResource* fbo) {
5923  if (id != active_framebuffer_) {
5924  DCHECK(!fbo || id == fbo->GetId());
5925  active_framebuffer_ = id;
5926  active_framebuffer_resource_ = fbo;
5927  GetGraphicsManager()->BindFramebuffer(GL_FRAMEBUFFER, id);
5928  }
5929 }
5930 
5931 bool Renderer::ResourceBinder::BindProgram(GLuint id,
5932  ShaderProgramResource* resource) {
5933  if (id != active_shader_id_) {
5934  DCHECK(!resource || id == resource->GetId());
5935  active_shader_id_ = id;
5936  GetGraphicsManager()->UseProgram(id);
5937  active_shader_resource_ = resource;
5938  return true;
5939  } else {
5940  return false;
5941  }
5942 }
5943 
5944 void Renderer::ResourceBinder::BindVertexArray(GLuint id,
5945  VertexArrayResource* resource) {
5946  if (id != active_vertex_array_) {
5947  DCHECK(!resource || id == resource->GetId());
5948  active_vertex_array_ = id;
5949  active_vertex_array_resource_ = resource;
5954  ClearBufferBinding(BufferObject::kElementBuffer, 0U);
5955  GetGraphicsManager()->BindVertexArray(id);
5956  }
5957 }
5958 
5959 void Renderer::ResourceBinder::ActivateUnit(GLuint unit) {
5960  DCHECK_LT(unit, static_cast<GLuint>(image_units_.size()));
5961  if (unit != active_image_unit_) {
5962  active_image_unit_ = unit;
5963  GetGraphicsManager()->ActiveTexture(GL_TEXTURE0 + unit);
5964  }
5965 }
5966 
5967 void Renderer::ResourceBinder::BindTextureToUnit(TextureResource* resource,
5968  GLuint unit) {
5969  DCHECK_LT(unit, image_units_.size());
5970 
5971  TextureResource* current_resource = image_units_[unit].resource;
5972  if (current_resource != resource) {
5973  ActivateUnit(unit);
5976  const GLuint id = resource->GetId();
5977  const GLenum target = resource->GetGlTarget();
5978  image_units_[unit].resource = resource;
5979  texture_last_bindings_[resource] = unit;
5980  GetGraphicsManager()->BindTexture(target, id);
5981  }
5982 }
5983 
5984 void Renderer::ResourceBinder::ClearTextureBinding(GLuint id, GLuint unit) {
5985  TextureResource*& resource = image_units_[unit].resource;
5986  if (!id || (resource && id == resource->GetId())) {
5987  resource = nullptr;
5988  }
5989 }
5990 
5991 void Renderer::ResourceBinder::ClearVertexArrayBinding(GLuint id) {
5992  if (!id || id == active_vertex_array_) {
5993  active_vertex_array_ = 0;
5994  if (active_vertex_array_resource_ &&
5995  active_vertex_array_resource_->GetElementArrayBinding().buffer) {
5996  ClearBufferBinding(
5998  active_vertex_array_resource_->GetElementArrayBinding().buffer);
5999  }
6000  active_vertex_array_resource_ = nullptr;
6001  }
6002 }
6003 
6004 void Renderer::ResourceBinder::ClearNonFramebufferCachedBindings() {
6005  ClearBufferBinding(BufferObject::kArrayBuffer, 0U);
6006  ClearBufferBinding(BufferObject::kElementBuffer, 0U);
6007  ClearProgramBinding(0U);
6008  const GLuint count = static_cast<GLuint>(GetImageUnitCount());
6009  for (GLuint i = 0U; i < count; ++i) {
6010  ClearTextureBinding(0U, i);
6011  image_units_[i].sampler = 0;
6012  }
6013  active_image_unit_ = static_cast<GLuint>(image_units_.size() + 1U);
6014  ClearVertexArrayBinding(0U);
6015 }
6016 
6017 const ImagePtr Renderer::ResourceBinder::ReadImage(
6018  const math::Range2i& range, Image::Format format,
6019  const base::AllocatorPtr& allocator) {
6020  ImagePtr image(new(allocator) Image());
6021  const int x = range.GetMinPoint()[0];
6022  const int y = range.GetMinPoint()[1];
6023  const int width = range.GetSize()[0];
6024  const int height = range.GetSize()[1];
6025 
6026  GraphicsManager* gm = GetGraphicsManager().Get();
6027  Image::PixelFormat pf =
6028  GetCompatiblePixelFormat(Image::GetPixelFormat(format), gm);
6029  const size_t data_size = Image::ComputeDataSize(format, width, height);
6030  DataContainerPtr data = DataContainer::CreateOverAllocated<uint8>(
6031  data_size, nullptr, image->GetAllocator());
6032  memset(data->GetMutableData<uint8>(), 0, data_size);
6033 
6034  gm->PixelStorei(GL_PACK_ALIGNMENT, 1);
6035  gm->ReadPixels(x, y, width, height, pf.format, pf.type,
6036  data->GetMutableData<uint8>());
6037  image->Set(format, width, height, data);
6038 
6039  return image;
6040 }
6041 
6042 void Renderer::ResourceBinder::SendUniform(const Uniform& uniform, int location,
6043  GraphicsManager* gm) {
6044 #define SEND_VECTOR_UNIFORM(type, elem_type, num_elements, setter) \
6045  if (uniform.IsArrayOf<type>()) { \
6046  /* Check that the values are packed in the uniform data. */ \
6047  if (uniform.GetCount() > 1) { \
6048  DCHECK_EQ( \
6049  reinterpret_cast<const elem_type*>(&uniform.GetValueAt<type>(1)), \
6050  reinterpret_cast<const elem_type*>(&uniform.GetValueAt<type>(0)) + \
6051  num_elements); \
6052  } \
6053  gm->setter( \
6054  location, static_cast<GLsizei>(uniform.GetCount()), \
6055  reinterpret_cast<const elem_type*>(&uniform.GetValueAt<type>(0))); \
6056  } else { \
6057  gm->setter(location, 1, \
6058  reinterpret_cast<const elem_type*>(&uniform.GetValue<type>())); \
6059  }
6060 
6061 #define SEND_TEXTURE_UNIFORM(type) \
6062  /* Get the texture resource from each holder. */ \
6063  if (uniform.IsArrayOf<type##Ptr>()) { \
6064  const size_t count = uniform.GetCount(); \
6065  const base::AllocatorPtr& allocator = \
6066  base::AllocationManager::GetDefaultAllocatorForLifetime( \
6067  base::kShortTerm); \
6068  base::AllocVector<GLint> ids(allocator); \
6069  ids.reserve(count); \
6070  /* Each resource holds its own id. */ \
6071  for (size_t i = 0; i < count; ++i) \
6072  if (TextureResource* txr = resource_manager_->GetResource( \
6073  uniform.GetValueAt<type##Ptr>(i).Get(), this)) \
6074  ids.push_back(GetLastBoundUnit(txr)); \
6075  gm->Uniform1iv(location, static_cast<GLsizei>(count), &ids[0]); \
6076  } else if (TextureResource* txr = resource_manager_->GetResource( \
6077  uniform.GetValue<type##Ptr>().Get(), this)) { \
6078  gm->Uniform1i(location, GetLastBoundUnit(txr)); \
6079  }
6080 
6084  switch (uniform.GetType()) {
6085  case kIntUniform:
6086  SEND_VECTOR_UNIFORM(int, int, 1, Uniform1iv);
6087  break;
6088  case kFloatUniform:
6089  SEND_VECTOR_UNIFORM(float, float, 1, Uniform1fv);
6090  break;
6091  case kUnsignedIntUniform:
6092  SEND_VECTOR_UNIFORM(uint32, uint32, 1, Uniform1uiv);
6093  break;
6095  SEND_TEXTURE_UNIFORM(CubeMapTexture);
6096  break;
6097  case kTextureUniform:
6098  SEND_TEXTURE_UNIFORM(Texture);
6099  break;
6100  case kFloatVector2Uniform:
6101  SEND_VECTOR_UNIFORM(math::VectorBase2f, float, 2, Uniform2fv);
6102  break;
6103  case kFloatVector3Uniform:
6104  SEND_VECTOR_UNIFORM(math::VectorBase3f, float, 3, Uniform3fv);
6105  break;
6106  case kFloatVector4Uniform:
6107  SEND_VECTOR_UNIFORM(math::VectorBase4f, float, 4, Uniform4fv);
6108  break;
6109  case kIntVector2Uniform:
6110  SEND_VECTOR_UNIFORM(math::VectorBase2i, int, 2, Uniform2iv);
6111  break;
6112  case kIntVector3Uniform:
6113  SEND_VECTOR_UNIFORM(math::VectorBase3i, int, 3, Uniform3iv);
6114  break;
6115  case kIntVector4Uniform:
6116  SEND_VECTOR_UNIFORM(math::VectorBase4i, int, 4, Uniform4iv);
6117  break;
6119  SEND_VECTOR_UNIFORM(math::VectorBase2ui, uint32, 2, Uniform2uiv);
6120  break;
6122  SEND_VECTOR_UNIFORM(math::VectorBase3ui, uint32, 3, Uniform3uiv);
6123  break;
6125  SEND_VECTOR_UNIFORM(math::VectorBase4ui, uint32, 4, Uniform4uiv);
6126  break;
6127  case kMatrix2x2Uniform:
6128  SendMatrixUniform<2>(uniform, gm, location,
6130  break;
6131  case kMatrix3x3Uniform:
6132  SendMatrixUniform<3>(uniform, gm, location,
6133  &GraphicsManager::UniformMatrix3fv);
6134  break;
6135  case kMatrix4x4Uniform: {
6136  SendMatrixUniform<4>(uniform, gm, location,
6138  break;
6139  }
6140 #if !defined(ION_COVERAGE) // COV_NF_START
6141  default:
6143  break;
6144 #endif // COV_NF_END
6145  }
6146 #undef SEND_VECTOR_UNIFORM
6147 #undef SEND_TEXTURE_UNIFORM
6148 }
6149 
6150 void Renderer::ResourceManager::DisassociateElementBufferFromArrays(
6151  BufferResource* resource) {
6152  ResourceAccessor accessor(resources_[kAttributeArray]);
6153  ResourceVector& resources = accessor.GetResources();
6154  const size_t count = resources.size();
6155  for (size_t i = 0; i < count; ++i) {
6156  VertexArrayResource* res =
6157  reinterpret_cast<VertexArrayResource*>(resources[i]);
6158  if (res->GetElementArrayBinding().resource == resource)
6159  res->SetElementArrayBinding(0, nullptr);
6160  }
6161 }
6162 
6163 void Renderer::ResourceBinder::PushUniforms(
6164  const Node* node, const base::AllocVector<Uniform>& uniforms) {
6165  const size_t num_uniforms = uniforms.size();
6166  for (size_t i = 0; i < num_uniforms; ++i) {
6167  ShaderInputRegistryResource* sirr =
6168  resource_manager_->GetResource(&uniforms[i].GetRegistry(), this);
6169  sirr->Update(this);
6170  sirr->PushUniform(uniforms[i]);
6171  }
6172 }
6173 
6174 void Renderer::ResourceBinder::PopUniforms(
6175  const base::AllocVector<Uniform>& uniforms) {
6176  const size_t num_uniforms = uniforms.size();
6177  for (size_t i = 0; i < num_uniforms; ++i) {
6178  ShaderInputRegistryResource* sirr =
6179  resource_manager_->GetResource(&uniforms[i].GetRegistry(), this);
6180  sirr->PopUniform(uniforms[i]);
6181  }
6182 }
6183 
6184 template <typename HolderType>
6185 typename Renderer::HolderToResource<HolderType>::ResourceType*
6186 Renderer::ResourceManager::CreateResource(const HolderType* holder,
6187  Renderer::ResourceBinder* binder,
6188  ResourceKey key, GLuint gl_id) {
6189  typedef typename HolderToResource<HolderType>::ResourceType ResourceType;
6191  const base::AllocatorPtr& allocator =
6192  holder->GetAllocator().Get() ? holder->GetAllocator()
6193  : GetAllocatorForLifetime(base::kMediumTerm);
6194  ResourceType* new_resource =
6195  new (allocator) ResourceType(binder, this, *holder, key, gl_id);
6196  AddResource(new_resource);
6197  return new_resource;
6198 }
6199 
6200 template <typename HolderType>
6201 typename Renderer::HolderToResource<HolderType>::ResourceType*
6202 Renderer::ResourceManager::GetResource(
6203  const HolderType* holder, Renderer::ResourceBinder* resource_binder,
6204  GLuint gl_id) {
6205  typedef typename HolderToResource<HolderType>::ResourceType ResourceType;
6206 
6207  DCHECK(holder);
6208  ResourceType* resource = nullptr;
6209  if (holder) {
6213  const ResourceKey key =
6214  GetResourceKey<ResourceType>(resource_binder, holder);
6215  if (Resource* holder_resource =
6216  static_cast<Resource*>(holder->GetResource(resource_index_, key))) {
6217  resource = static_cast<ResourceType*>(holder_resource);
6218  } else {
6220  resource = CreateResource(holder, resource_binder, key, gl_id);
6221  holder->SetResource(resource_index_, key, resource);
6222  }
6223  }
6224  return resource;
6225 }
6226 
6228 template <>
6229 void Renderer::ResourceManager::FillDataFromRenderer(GLuint id,
6230  PlatformInfo* info) {}
6231 
6232 template <>
6233 void Renderer::ResourceManager::FillDataFromRenderer(GLuint id,
6234  TextureImageInfo* info) {
6236  ResourceAccessor accessor(resources_[kTexture]);
6237  ResourceVector& resources = accessor.GetResources();
6238  if (const size_t count = resources.size()) {
6239  for (size_t i = 0; i < count; ++i) {
6240  TextureResource* tr = reinterpret_cast<TextureResource*>(resources[i]);
6241  if (static_cast<GLuint>(tr->GetId()) == id) {
6243  info->texture.Reset(
6244  const_cast<TextureBase*>(&tr->GetTexture<TextureBase>()));
6245  if (info->texture->GetTextureType() == TextureBase::kCubeMapTexture) {
6246  const CubeMapTexture& tex = tr->GetTexture<CubeMapTexture>();
6247  for (int f = 0; f < 6; ++f) {
6248  info->images.push_back(GetCubeMapTextureImageOrMipmap(
6249  tex, static_cast<CubeMapTexture::CubeFace>(f)));
6250  }
6251  } else {
6252  const Texture& tex = tr->GetTexture<Texture>();
6253  info->images.push_back(GetTextureImageOrMipmap(tex));
6254  }
6255  }
6256  }
6257  }
6258 }
6259 
6261 template <>
6262 void Renderer::ResourceManager::FillInfoFromResource(
6263  ArrayInfo* info, VertexArrayResource* resource, ResourceBinder* rb) {
6264  info->vertex_count = resource->GetVertexCount();
6265 }
6266 
6267 template <>
6268 void Renderer::ResourceManager::FillInfoFromResource(BufferInfo* info,
6269  BufferResource* resource,
6270  ResourceBinder* rb) {
6271  info->target = resource->GetGlTarget();
6272 }
6273 
6274 template <>
6275 void Renderer::ResourceManager::FillInfoFromResource(
6276  FramebufferInfo* info, FramebufferResource* resource, ResourceBinder* rb) {
6277  info->color0_renderbuffer.id = resource->GetColor0Id();
6278  info->depth_renderbuffer.id = resource->GetDepthId();
6279  info->stencil_renderbuffer.id = resource->GetStencilId();
6280 }
6281 
6282 template <>
6283 void Renderer::ResourceManager::FillInfoFromResource(
6284  ProgramInfo* info, ShaderProgramResource* resource, ResourceBinder* rb) {
6285  if (ShaderResource* shader = resource->GetVertexResource())
6286  info->vertex_shader = shader->GetId();
6287  if (ShaderResource* shader = resource->GetFragmentResource())
6288  info->fragment_shader = shader->GetId();
6289 }
6290 
6291 template <>
6292 void Renderer::ResourceManager::FillInfoFromResource(
6293  TextureInfo* info, TextureResource* resource, ResourceBinder* rb) {
6294  info->unit = GL_TEXTURE0 + rb->GetLastBoundUnit(resource);
6295  info->target = resource->GetGlTarget();
6296  const Texture::TextureType type =
6297  resource->GetTexture<TextureBase>().GetTextureType();
6298  info->width = info->height = 0U;
6299  info->format = base::InvalidEnumValue<Image::Format>();
6300  Image* image = nullptr;
6301  if (type == TextureBase::kTexture) {
6302  const Texture& tex = resource->GetTexture<Texture>();
6303  if (tex.HasImage(0U))
6304  image = tex.GetImage(0U).Get();
6305  } else { // kCubeMapTexture.
6306  const CubeMapTexture& tex = resource->GetTexture<CubeMapTexture>();
6307  if (tex.HasImage(CubeMapTexture::kNegativeX, 0))
6308  image = tex.GetImage(CubeMapTexture::kNegativeX, 0).Get();
6309  }
6310  if (image) {
6311  info->format = image->GetFormat();
6312  info->width = image->GetWidth();
6313  info->height = image->GetHeight();
6314  }
6315 }
6316 
6318 template Renderer::BufferResource* Renderer::ResourceManager::GetResource(
6319  const BufferObject*, Renderer::ResourceBinder*, GLuint);
6320 template Renderer::TextureResource* Renderer::ResourceManager::GetResource(
6321  const CubeMapTexture*, Renderer::ResourceBinder*, GLuint);
6322 template Renderer::FramebufferResource* Renderer::ResourceManager::GetResource(
6323  const FramebufferObject*, Renderer::ResourceBinder*, GLuint);
6324 template Renderer::SamplerResource* Renderer::ResourceManager::GetResource(
6325  const Sampler*, Renderer::ResourceBinder*, GLuint);
6326 template Renderer::ShaderResource* Renderer::ResourceManager::GetResource(
6327  const Shader*, Renderer::ResourceBinder*, GLuint);
6328 template Renderer::ShaderProgramResource*
6329 Renderer::ResourceManager::GetResource(const ShaderProgram*,
6330  Renderer::ResourceBinder*, GLuint);
6331 template Renderer::TextureResource* Renderer::ResourceManager::GetResource(
6332  const Texture*, Renderer::ResourceBinder*, GLuint);
6333 template Renderer::VertexArrayResource* Renderer::ResourceManager::GetResource(
6334  const AttributeArray*, Renderer::ResourceBinder*, GLuint);
6335 
6336 } // namespace gfx
6337 } // namespace ion
GraphicsManager manages the graphics library for an application.
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
Definition: invalid.h:41
std::string buffer
#define GL_PROGRAM_OBJECT
Definition: glheaders.h:624
const StateTable & GetStateTable() const
Returns the StateTable that the Renderer believes to represent the current state of OpenGL...
Definition: renderer.cc:5473
kShortTerm is used for objects that are very transient in nature, such as scratch memory used to comp...
Definition: allocator.h:36
virtual void DrawScene(const NodePtr &node)
Draws the scene rooted by the given node into the currently bound framebuffer.
Definition: renderer.cc:5181
This is used for Apple devices running pre-es-3.0 device with the APPLE_framebuffer_multisample exten...
const AllocationTrackerPtr & GetTracker() const
Definition: allocator.h:82
static uint32 GetConstant(EnumType e)
Returns the constant value corresponding to an enum.
Definition: enumhelper.h:80
Matrix< 4, float > Matrix4f
Definition: matrix.h:371
base::ReferentPtr< Node >::Type NodePtr
Definition: node.h:33
base::ReferentPtr< FramebufferObject >::Type FramebufferObjectPtr
Convenience typedef for shared pointer to a FramebufferObject.
void ClearFromStateTable(const StateTable &new_state, StateTable *save_state, GraphicsManager *gm)
This internal function can be used to update the Clear()-related OpenGL state (dithering, scissor test, write masks, scissor box, and clear values) managed by a GraphicsManager to match a StateTable, and updates save_state to contain the new state.
#define SEND_TEXTURE_UNIFORM(type)
A Texture object represents the image data and mipmaps associated with a single texture.
Definition: texture.h:264
framebuffer alpha dfactor const GLvoid usage alpha const GLvoid data border const GLuint buffers const GLuint renderbuffers count renderbuffer GLuint framebuffers GLsizei GLint GLenum GLchar name GLsizei GLuint shaders GLint data GLsizei GLchar info_log GLint params GLint GLint precision GLint params GLint params GLint params GLfloat params GLvoid pointer height height const GLchar const GLint length mask dppass param param const GLvoid data const GLint1 value const GLfloat2 value v2 v2 v3 v3 const GLmatrix2 value UniformMatrix4fv
Format
Supported image formats.
Definition: image.h:38
#define ION_DECLARE_SAFE_STATIC_POINTER(type, variable)
Declare a static non-array pointer and calls a default constructor.
int level
T Log2(T n)
Returns the base-2 logarithm of n.
Definition: utils.h:148
CompareMode
Texture comparison modes for depth textures.
Definition: sampler.h:60
Flag
The below flags determine what operations will be performed in a call to DrawScene().
Definition: renderer.h:54
This class can be used in place of std::unordered_map to allow an Ion Allocator to be used for memory...
base::ReferentPtr< Image >::Type ImagePtr
Definition: image.h:29
#define ION_DECLARE_SAFE_STATIC_POINTER_WITH_CONSTRUCTOR(type, variable, constructor)
Declare a static non-array pointer and calls a non-default constructor.
ResourceManager(const GraphicsManagerPtr &gm)
A valid GraphicsManagerPtr must be passed to the constructor.
std::string type
Definition: printer.cc:353
const CubeMapTexturePtr & GetCubeMapTexture() const
Gets the cubemap of the attachment, if any.
SharedPtr< AllocationSizeTracker > AllocationSizeTrackerPtr
Convenience typedef for shared pointer to a AllocationSizeTracker.
base::ReferentPtr< Shape >::Type ShapePtr
Convenience typedef for shared pointer to a Shape.
Definition: shape.h:167
static size_t GetCurrentId()
Returns a unique ID for the currently bound Visual.
Definition: visual.cc:313
An IndexBuffer is a type of BufferObject that contains the element indices of an array, e.g., a vertex index array.
Definition: indexbuffer.h:28
#define GL_LUMINANCE_ALPHA
Definition: glheaders.h:468
Range< 1, int32 > Range1i
Definition: range.h:363
Process any outstanding requests for information about internal resources that have been made through...
Definition: renderer.h:57
A ShaderProgram represents an OpenGL shader program that can be applied to shapes.
Definition: shaderprogram.h:38
static const Visual * GetCurrent()
Returns the Visual that is current for the calling thread.
Definition: visual.cc:213
ResourceType
The types of resources created by the renderer.
Definition: renderer.h:101
const size_t kInvalidIndex
kInvalidIndex is a size_t value that is very unlikely to be a valid index.
Definition: invalid.cc:23
void ClearAllResources()
Immediately clears all internal resources of the Renderer.
Definition: renderer.cc:5608
static void DestroyCurrentStateCache()
Destroys the internal state cache associated with the current Visual or GL context.
Definition: renderer.cc:4790
#define DCHECK(expr)
Definition: logging.h:331
GenericLockGuard< port::Mutex > LockGuard
Convenient typedefs for ion::port::Mutex.
Definition: lockguards.h:192
double value
#define SEND_VECTOR_UNIFORM(type, elem_type, num_elements, setter)
void ProcessStateTable(const StateTablePtr &state_table)
Immediately updates OpenGL state with the settings in the passed StateTable.
Definition: renderer.cc:4925
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
static const Flags & AllFlags()
Convenience functions that return std::bitsets of Flags.
Definition: renderer.cc:4716
framebuffer alpha dfactor const GLvoid usage alpha const GLvoid data border const GLuint buffers const GLuint renderbuffers count renderbuffer GLuint framebuffers GLsizei GLint GLenum GLchar name GLsizei GLuint shaders GLint data GLsizei GLchar info_log GLint params GLint GLint precision GLint params GLint params GLint params GLfloat params GLvoid pointer height height const GLchar const GLint length mask dppass param param const GLvoid data const GLint1 value const GLfloat2 value v2 v2 v3 v3 UniformMatrix2fv
Matrix< 3, float > Matrix3f
Definition: matrix.h:369
base::ReferentPtr< CubeMapTexture >::Type CubeMapTexturePtr
Convenience typedef for shared pointer to a CubeMapTexture.
const GraphicsManagerPtr & GetGraphicsManager() const
Functions.
const TexturePtr & GetTexture() const
Gets the texture of the attachment, if any.
Whether to query OpenGL for current states and save them, which can be restored using the above kRest...
Definition: renderer.h:89
CubeFace
The names of faces of the cube map.
#define DCHECK_GT(val1, val2)
Definition: logging.h:337
const ShaderInputRegistry & GetRegistry() const
Returns the ShaderInputRegistry the shader input is defined in.
Definition: shaderinput.h:63
A Uniform instance represents a uniform shader argument.
Definition: uniform.h:76
#define GL_SAMPLER_EXTERNAL_OES
Definition: glheaders.h:912
void ProcessResourceInfoRequests()
Process any outstanding requests for information about internal resources that have been made through...
Definition: renderer.cc:5454
static const Flags & AllProcessFlags()
Definition: renderer.cc:4735
uint32 offset
virtual const AllocatorPtr & GetAllocatorForLifetime(AllocationLifetime lifetime) const
Returns the correct Allocator to use to allocate memory with a specific lifetime. ...
Definition: allocator.cc:27
~Renderer() override
The destructor is protected because all base::Referent classes must have protected or private destruc...
Definition: renderer.cc:4704
void UpdateStateFromOpenGL(int window_width, int window_height)
A Renderer manages graphics state using a StateTable.
Definition: renderer.cc:5460
Capability
Enumerated types for StateTable items.
Definition: statetable.h:55
size_t vertex_count
void ResolveMultisampleFramebuffer(const FramebufferObjectPtr &ms_fbo, const FramebufferObjectPtr &dest_fbo)
Resolve a multisampled framebuffer 'ms_fbo' into a single sampled framebuffer 'dest_fbo'.
Definition: renderer.cc:5142
Range< 2, int32 > Range2i
Definition: range.h:371
WrapMode
Texture filter modes.
Definition: sampler.h:77
A FramebufferObject describes an off-screen framebuffer that can be drawn to and read from like a reg...
uint32 length
#define GL_BUFFER_OBJECT
Definition: glheaders.h:165
Range< 1, uint32 > Range1ui
Definition: range.h:364
Scalar types.
Definition: uniform.h:39
base::ReferentPtr< StateTable >::Type StateTablePtr
Convenience typedef for shared pointer to a StateTable.
Definition: statetable.h:705
SharedPtr< Allocator > AllocatorPtr
Definition: allocator.h:51
std::string label
Definition: printer.cc:354
Whether to restore certain GL state types when drawing is finished.
Definition: renderer.h:78
void RequestForcedUpdate(T *holder)
Mark an object for a forced update of GL resources.
#define GL_POINT_SPRITE
Definition: glheaders.h:618
static void DestroyStateCache(const portgfx::Visual *visual)
Destroys the internal state cache associated with the passed Visual.
Definition: renderer.cc:4780
uint32 id
const ResourceHolder * GetHolder() const
Retrieve the holder for which this resource was created.
Definition: resourcebase.h:47
const AllocatorPtr & GetAllocatorForLifetime(AllocationLifetime lifetime) const
Convenience function that returns the Allocator to use to allocate an object with a specific lifetime...
Definition: allocatable.h:78
static const Flags & AllRestoreFlags()
Definition: renderer.cc:4741
static size_t ComputeDataSize(Format format, uint32 width, uint32 height)
Convenience functions that return the correct data size in bytes of an image having the given format ...
Definition: image.cc:421
void UpdateStateTable(int default_width, int default_height, GraphicsManager *gm, StateTable *st)
Public functions.
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
A LockGuard locks a mutex when created, and unlocks it when destroyed.
Definition: lockguards.h:90
void ClearTypedResources(ResourceType type)
Immediately clears the internal resources of all ResourceHolders of the passed type.
Definition: renderer.cc:5614
std::string ValueToString(const T &val)
ValueToString.
Definition: serialize.h:209
A ShaderInputRegistry is used to manage a collection of shader inputs to a specific ShaderProgram (bo...
std::bitset< kNumFlags > Flags
Definition: renderer.h:98
A BufferObject describes a generic array of data used, for example, to describe the vertices in a Sha...
Definition: bufferobject.h:67
Release any internal resources that have been marked for destruction, including OpenGL objects...
Definition: renderer.h:60
static const Flags & AllSaveFlags()
Definition: renderer.cc:4752
static bool GetMerged(const Uniform &base, const Uniform &replacement, Uniform *merged)
Merges replacement and base into merged.
Definition: uniform.cc:225
void FillInfoFromOpenGL(InfoType *info)
Performs OpenGL calls to fill in info details, specialized for each type derived from ResourceInfo...
static const PixelFormat & GetPixelFormat(Format format)
Convenience function that returns a PixelFormat given a Format.
Definition: image.cc:76
void ClearResources(const HolderType *holder)
Immediately clears the internal resources of the passed ResourceHolder.
const GraphicsManagerPtr & GetGraphicsManager() const
Returns the GraphicsManager passed to the constructor.
Definition: renderer.cc:4763
These are necessary since each column of a matrix must be sent to OpenGL separately and we must know ...
Definition: bufferobject.h:88
static const Spec< T > * GetSpec(const T &input)
Convenience function that returns a pointer to the Spec associated with an Attribute or Uniform insta...
void UnmapBufferObjectData(const BufferObjectPtr &buffer)
Unmaps a previously mapped BufferObject and makes the data available to the graphics hardware...
Definition: renderer.cc:5512
void PopDebugMarker()
In non-production builds, pops a label off of the Renderer's tracing stream marker stack...
Definition: renderer.cc:5541
The entries between kAttributeChanged and kAttributeEnabledChanged are reserved for determining which...
void SetConcurrent(bool value)
Sets/returns whether this shader program should have per-thread state.
static const char * GetString(EnumType e)
Returns a string corresponding to an enum.
Definition: enumhelper.h:59
std::string name
Definition: printer.cc:324
BufferObjectDataMapMode
The possible ways a BufferObject's data can be mapped.
Definition: renderer.h:117
Allocatable()
This constructor sets up the Allocator pointer.
Definition: allocatable.cc:253
void BindResource(T *holder)
Immediately creates internal GL resources for the passed holder, uploading any data and binding the r...
const FramebufferObjectPtr GetCurrentFramebuffer() const
Returns the currently bound FramebufferObject.
Definition: renderer.cc:4857
An AttributeArray represents a collection of Attributes used to describe the vertices of a Shape...
void CreateOrUpdateResource(T *holder)
This function is useful for uploading data to the hardware at a time convenient to the caller when us...
4444 uint16 data.
Definition: image.h:166
#define GL_SHADER_OBJECT
Definition: glheaders.h:924
ComponentType
The type of the components of a spec.
Definition: bufferobject.h:77
void SetInitialUniformValue(const Uniform &u)
Sets the initial value of a Uniform to the passed value.
Definition: renderer.cc:5129
const Grid & image
The original monochrome image data, as doubles (0 - 1).
Definition: sdfutils.cc:90
#define DCHECK_GE(val1, val2)
Definition: logging.h:336
base::ReferentPtr< Shader >::Type ShaderPtr
Convenience typedef for shared pointers to Shaders.
#define LOG_ONCE(severity)
Logs the streamed message once per process run with a severity of severity.
Definition: logging.h:219
void RequestForcedShapeUpdates(const ShapePtr &shape)
Mark a shape's resources for a forced update the next time CreateOrUpdateResources or DrawScene is ca...
Definition: renderer.cc:5105
EnumType InvalidEnumValue()
InvalidEnumValue() returns an invalid enum value, assuming that -1 is not a valid value...
Definition: invalid.h:47
This covers both OES_EGL_image and OES_EGL_image_external.
GenericLockGuard< ReadLock > ReadGuard
Convenient typedefs for ReadWriteLock.
Definition: lockguards.h:202
size_t GetId() const
Returns the ID associated with this Visual.
Definition: visual.h:54
static const Flags & AllClearFlags()
Definition: renderer.cc:4722
ResourceKey GetKey() const
Retrieve a key that disambiguates between multiple resources created for the same holder by the same ...
Definition: resourcebase.h:51
Whether to clear (set to 0) certain GL objects when drawing is finished.
Definition: renderer.h:65
A ResourceManager is an interface for getting information about a Renderer's internal resources...
size_t GetGpuMemoryUsage(ResourceType type) const
Returns the amount of GPU memory used by the passed resource type.
Definition: renderer.cc:5625
Copyright 2016 Google Inc.
uint32 GetResourceGlId(T *holder)
Returns the OpenGL ID for the passed resource.
Definition: renderer.cc:5549
Matrix types.
Definition: uniform.h:59
const std::string indent_
void RequestForcedUpdates(const NodePtr &node)
Mark the passed object and its descendants for a forced resource update the next time CreateOrUpdateR...
Definition: renderer.cc:5095
Opaque class that sets up an offscreen OpenGL context/surface/visual in a platform-specific way to al...
Definition: visual.h:40
int width
Matrix< 2, float > Matrix2f
Dimension- and type-specific typedefs.
Definition: matrix.h:367
static int GetNumComponentsForFormat(Format format)
Convenience function that returns the number of components for a given format.
Definition: image.cc:315
A WriteLock obtains a write lock, but has a similar interface to a Mutex and can be used with a Write...
void UpdateFromStateTable(const StateTable &new_state, StateTable *save_state, GraphicsManager *gm)
This internal function can be used to update the OpenGL state managed by a GraphicsManager to match a...
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
TexturePtr texture
The Texture to add sub-image data to.
Definition: fontimage.cc:107
ResourceBase * GetResource(size_t index, ResourceKey key) const
Returns the Resource at the given index and key, or NULL if no resource was previously set at that lo...
void SetTextureImageUnitRange(const math::Range1i &units)
Sets the inclusive range of texture image units that the Renderer should use.
Definition: renderer.cc:5580
#define ION_PRETTY_FUNCTION
Make ION_PRETTY_FUNCTION available on all platforms.
Definition: macros.h:46
base::ReferentPtr< GraphicsManager >::Type GraphicsManagerPtr
Convenience typedef for shared pointer to a GraphicsManager.
A CubeMapTexture object represents the image data and mipmaps associated with the six faces of a cube...
void CreateOrUpdateShapeResources(const ShapePtr &shape)
Creates or updates any resources necessary to draw the passed Shape, i.e., buffer data is uploaded...
Definition: renderer.cc:5059
#define DCHECK_LE(val1, val2)
Definition: logging.h:334
bool IsPowerOfTwo(int value)
Returns true if a value is a power of two.
Definition: utils.h:216
virtual AllocationSizeTrackerPtr GetGpuTracker()=0
#define GL_TEXTURE_EXTERNAL_OES
Definition: glheaders.h:1029
intptr_t ResourceKey
Type of identifiers used to disambiguate between multiple resources created for the same Ion object b...
Definition: resourcebase.h:27
static bool ExpectedDimensionsForMipmap(const uint32 mipmap_width, const uint32 mipmap_height, const uint32 mipmap_level, const uint32 base_width, const uint32 base_height, uint32 *expected_width, uint32 *expected_height)
Tests mipmap dimensions to see that they are proportional and in range with respect to base_width and...
Definition: texture.cc:140
A Shader represents an OpenGL shader stage.
Definition: shader.h:59
Scalar types.
Definition: attribute.h:35
void * AllocateMemory(size_t size)
Allocates memory of the given size.
Definition: allocator.cc:32
base::ReferentPtr< ShaderInputRegistry >::Type ShaderInputRegistryPtr
Convenience typedef for shared pointer to a ShaderInputRegistry.
void BindFramebuffer(const FramebufferObjectPtr &fbo)
Binds the passed FramebufferObject; all future calls to DrawScene() will be drawn into it...
Definition: renderer.cc:4839
void CreateOrUpdateResources(const NodePtr &node)
Traverses the scene rooted by the given node and creates or updates resources for ShaderPrograms...
Definition: renderer.cc:4965
void ReleaseResources()
Immediately releases all internal resources of the Renderer which are pending release.
Definition: renderer.cc:5619
const ImagePtr ReadImage(const math::Range2i &range, Image::Format format, const base::AllocatorPtr &allocator)
Returns an image of the specified format that contains the contents of the hardware framebuffer...
Definition: renderer.cc:5524
void MapBufferObjectDataRange(const BufferObjectPtr &buffer, BufferObjectDataMapMode mode, const math::Range1ui &range)
This function maps a DataContainer with the size of the passed range.
Definition: renderer.cc:5498
bool IsConcurrent() const
Definition: shaderprogram.h:89
A ReadLock obtains a read lock, but has a similar interface to a Mutex and can be used with a ReadGua...
Definition: readwritelock.h:86
base::ReferentPtr< DataContainer >::Type DataContainerPtr
Definition: datacontainer.h:38
These are only usable with the minification filter.
Definition: sampler.h:70
base::ReferentPtr< BufferObject >::Type BufferObjectPtr
Convenience typedef for shared pointer to a BufferObject.
Definition: bufferobject.h:31
A StateTable represents a collection of graphical state items that affect OpenGL rendering.
Definition: statetable.h:48
gfx::ResourceManager * GetResourceManager() const
Returns the ResourceManager for this renderer.
Definition: renderer.cc:4767
bool IsValid() const
Returns true if this is a valid instance created by a ShaderInputRegistry.
Definition: shaderinput.h:59
port::Mutex mutex_
Protects shared access to the Allocator and FT_Library.
An attachment represents a data store attached to one of the framebuffer's targets.
kMipmapChanged must be last since it is a range of slots.
Definition: texture.h:270
const AllocatorPtr & GetAllocator() const
Returns the Allocator that was used for the instance.
Definition: allocatable.h:68
kLongTerm is used for objects that have persistent lifetimes, such as managers.
Definition: allocator.h:44
#define GL_LUMINANCE
Definition: glheaders.h:465
void PushDebugMarker(const std::string &marker)
In non-production builds, pushes marker onto the Renderer's tracing stream marker stack...
Definition: renderer.cc:5536
void MapBufferObjectData(const BufferObjectPtr &buffer, BufferObjectDataMapMode mode)
In the below MapBuffer functions the passed BufferObject is assigned a DataContainer (retrievable via...
Definition: renderer.cc:5485
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
kMediumTerm is used for objects that don't fall into the kShortTerm or kLongTerm categories.
Definition: allocator.h:40
Renderer(const GraphicsManagerPtr &gm)
The constructor is passed a GraphicsManager instance to use for rendering.
Definition: renderer.cc:4694
void UpdateDefaultFramebufferFromOpenGL()
Updates the system default framebuffer to whatever framebuffer is currently bound.
Definition: renderer.cc:4863
ResourceBase(const ResourceHolder *holder, ResourceKey key)
The constructor accepts a holder parameter to simplify control flow during construction.
Definition: resourcebase.h:41
FilterMode
Texture filter modes.
Definition: sampler.h:66
GenericLockGuard< WriteLock > WriteGuard
Definition: lockguards.h:203
Matrix< Dimension, T > Transpose(const Matrix< Dimension, T > &m)
Public functions.
Definition: matrixutils.h:65
void operator=(const Allocatable &other)
The assignment operator does nothing, since all members are intrinsically tied to a particular alloca...
Definition: allocatable.h:133
ResourceHolder is an internal base class for objects that hold resources managed by an outside entity...
base::ReferentPtr< Texture >::Type TexturePtr
Convenience typedef for shared pointer to a Texture.
Definition: texture.h:333
#define GL_VERTEX_ARRAY_OBJECT
Definition: glheaders.h:1170
#define DCHECK_LT(val1, val2)
Definition: logging.h:335
static const int kNumResourceTypes
Definition: renderer.h:111
static const AllocatorPtr & GetDefaultAllocatorForLifetime(AllocationLifetime lifetime)
A Sampler object represents texture parameters that control how texture data is accessed in shaders...
Definition: sampler.h:29
CompareFunction
Texture comparison functions for depth textures.
Definition: sampler.h:48
void ClearCachedBindings()
Notifies the Renderer that it cannot rely on internally cached bindings; the next objects it encounte...
Definition: renderer.cc:4869
void UpdateStateFromStateTable(const StateTablePtr &state_to_clear)
This is more efficient than UpdateStateFromOpenGL().
Definition: renderer.cc:5467