1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gpu/command_buffer/service/texture_manager.h"
6 #include "base/bits.h"
7 #include "base/strings/stringprintf.h"
8 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
9 #include "gpu/command_buffer/service/context_state.h"
10 #include "gpu/command_buffer/service/error_state.h"
11 #include "gpu/command_buffer/service/feature_info.h"
12 #include "gpu/command_buffer/service/framebuffer_manager.h"
13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14 #include "gpu/command_buffer/service/mailbox_manager.h"
15 #include "gpu/command_buffer/service/memory_tracking.h"
16
17 namespace gpu {
18 namespace gles2 {
19
GLTargetToFaceIndex(GLenum target)20 static size_t GLTargetToFaceIndex(GLenum target) {
21 switch (target) {
22 case GL_TEXTURE_2D:
23 case GL_TEXTURE_EXTERNAL_OES:
24 case GL_TEXTURE_RECTANGLE_ARB:
25 return 0;
26 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
27 return 0;
28 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
29 return 1;
30 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
31 return 2;
32 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
33 return 3;
34 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
35 return 4;
36 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
37 return 5;
38 default:
39 NOTREACHED();
40 return 0;
41 }
42 }
43
FaceIndexToGLTarget(size_t index)44 static size_t FaceIndexToGLTarget(size_t index) {
45 switch (index) {
46 case 0:
47 return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
48 case 1:
49 return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
50 case 2:
51 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
52 case 3:
53 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
54 case 4:
55 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
56 case 5:
57 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
58 default:
59 NOTREACHED();
60 return 0;
61 }
62 }
63
DestructionObserver()64 TextureManager::DestructionObserver::DestructionObserver() {}
65
~DestructionObserver()66 TextureManager::DestructionObserver::~DestructionObserver() {}
67
~TextureManager()68 TextureManager::~TextureManager() {
69 for (unsigned int i = 0; i < destruction_observers_.size(); i++)
70 destruction_observers_[i]->OnTextureManagerDestroying(this);
71
72 DCHECK(textures_.empty());
73
74 // If this triggers, that means something is keeping a reference to
75 // a Texture belonging to this.
76 CHECK_EQ(texture_count_, 0u);
77
78 DCHECK_EQ(0, num_unrenderable_textures_);
79 DCHECK_EQ(0, num_unsafe_textures_);
80 DCHECK_EQ(0, num_uncleared_mips_);
81 DCHECK_EQ(0, num_images_);
82 }
83
Destroy(bool have_context)84 void TextureManager::Destroy(bool have_context) {
85 have_context_ = have_context;
86 textures_.clear();
87 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
88 default_textures_[ii] = NULL;
89 }
90
91 if (have_context) {
92 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
93 }
94
95 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
96 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
97 }
98
Texture(GLuint service_id)99 Texture::Texture(GLuint service_id)
100 : mailbox_manager_(NULL),
101 memory_tracking_ref_(NULL),
102 service_id_(service_id),
103 cleared_(true),
104 num_uncleared_mips_(0),
105 target_(0),
106 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
107 mag_filter_(GL_LINEAR),
108 wrap_s_(GL_REPEAT),
109 wrap_t_(GL_REPEAT),
110 usage_(GL_NONE),
111 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
112 max_level_set_(-1),
113 texture_complete_(false),
114 cube_complete_(false),
115 npot_(false),
116 has_been_bound_(false),
117 framebuffer_attachment_count_(0),
118 immutable_(false),
119 has_images_(false),
120 estimated_size_(0),
121 can_render_condition_(CAN_RENDER_ALWAYS),
122 texture_max_anisotropy_initialized_(false) {
123 }
124
~Texture()125 Texture::~Texture() {
126 if (mailbox_manager_)
127 mailbox_manager_->TextureDeleted(this);
128 }
129
AddTextureRef(TextureRef * ref)130 void Texture::AddTextureRef(TextureRef* ref) {
131 DCHECK(refs_.find(ref) == refs_.end());
132 refs_.insert(ref);
133 if (!memory_tracking_ref_) {
134 memory_tracking_ref_ = ref;
135 GetMemTracker()->TrackMemAlloc(estimated_size());
136 }
137 }
138
RemoveTextureRef(TextureRef * ref,bool have_context)139 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
140 if (memory_tracking_ref_ == ref) {
141 GetMemTracker()->TrackMemFree(estimated_size());
142 memory_tracking_ref_ = NULL;
143 }
144 size_t result = refs_.erase(ref);
145 DCHECK_EQ(result, 1u);
146 if (refs_.empty()) {
147 if (have_context) {
148 GLuint id = service_id();
149 glDeleteTextures(1, &id);
150 }
151 delete this;
152 } else if (memory_tracking_ref_ == NULL) {
153 // TODO(piman): tune ownership semantics for cross-context group shared
154 // textures.
155 memory_tracking_ref_ = *refs_.begin();
156 GetMemTracker()->TrackMemAlloc(estimated_size());
157 }
158 }
159
GetMemTracker()160 MemoryTypeTracker* Texture::GetMemTracker() {
161 DCHECK(memory_tracking_ref_);
162 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
163 }
164
LevelInfo()165 Texture::LevelInfo::LevelInfo()
166 : cleared(true),
167 target(0),
168 level(-1),
169 internal_format(0),
170 width(0),
171 height(0),
172 depth(0),
173 border(0),
174 format(0),
175 type(0),
176 estimated_size(0) {
177 }
178
LevelInfo(const LevelInfo & rhs)179 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
180 : cleared(rhs.cleared),
181 target(rhs.target),
182 level(rhs.level),
183 internal_format(rhs.internal_format),
184 width(rhs.width),
185 height(rhs.height),
186 depth(rhs.depth),
187 border(rhs.border),
188 format(rhs.format),
189 type(rhs.type),
190 image(rhs.image),
191 estimated_size(rhs.estimated_size) {
192 }
193
~LevelInfo()194 Texture::LevelInfo::~LevelInfo() {
195 }
196
GetCanRenderCondition() const197 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
198 if (target_ == 0)
199 return CAN_RENDER_ALWAYS;
200
201 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
202 if (level_infos_.empty()) {
203 return CAN_RENDER_NEVER;
204 }
205
206 const Texture::LevelInfo& first_face = level_infos_[0][0];
207 if (first_face.width == 0 ||
208 first_face.height == 0 ||
209 first_face.depth == 0) {
210 return CAN_RENDER_NEVER;
211 }
212 }
213
214 bool needs_mips = NeedsMips();
215 if (needs_mips) {
216 if (!texture_complete())
217 return CAN_RENDER_NEVER;
218 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
219 return CAN_RENDER_NEVER;
220 }
221
222 bool is_npot_compatible = !needs_mips &&
223 wrap_s_ == GL_CLAMP_TO_EDGE &&
224 wrap_t_ == GL_CLAMP_TO_EDGE;
225
226 if (!is_npot_compatible) {
227 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
228 return CAN_RENDER_NEVER;
229 else if (npot())
230 return CAN_RENDER_ONLY_IF_NPOT;
231 }
232
233 return CAN_RENDER_ALWAYS;
234 }
235
CanRender(const FeatureInfo * feature_info) const236 bool Texture::CanRender(const FeatureInfo* feature_info) const {
237 switch (can_render_condition_) {
238 case CAN_RENDER_ALWAYS:
239 return true;
240 case CAN_RENDER_NEVER:
241 return false;
242 case CAN_RENDER_ONLY_IF_NPOT:
243 break;
244 }
245 return feature_info->feature_flags().npot_ok;
246 }
247
AddToSignature(const FeatureInfo * feature_info,GLenum target,GLint level,std::string * signature) const248 void Texture::AddToSignature(
249 const FeatureInfo* feature_info,
250 GLenum target,
251 GLint level,
252 std::string* signature) const {
253 DCHECK(feature_info);
254 DCHECK(signature);
255 DCHECK_GE(level, 0);
256 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
257 level_infos_.size());
258 DCHECK_LT(static_cast<size_t>(level),
259 level_infos_[GLTargetToFaceIndex(target)].size());
260 const Texture::LevelInfo& info =
261 level_infos_[GLTargetToFaceIndex(target)][level];
262 *signature += base::StringPrintf(
263 "|Texture|target=%04x|level=%d|internal_format=%04x"
264 "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
265 "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
266 "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
267 "|usage=%04x",
268 target, level, info.internal_format,
269 info.width, info.height, info.depth, info.border,
270 info.format, info.type, info.image.get() != NULL,
271 CanRender(feature_info), CanRenderTo(), npot_,
272 min_filter_, mag_filter_, wrap_s_, wrap_t_,
273 usage_);
274 }
275
SetMailboxManager(MailboxManager * mailbox_manager)276 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
277 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
278 mailbox_manager_ = mailbox_manager;
279 }
280
MarkMipmapsGenerated(const FeatureInfo * feature_info)281 bool Texture::MarkMipmapsGenerated(
282 const FeatureInfo* feature_info) {
283 if (!CanGenerateMipmaps(feature_info)) {
284 return false;
285 }
286 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
287 const Texture::LevelInfo& info1 = level_infos_[ii][0];
288 GLsizei width = info1.width;
289 GLsizei height = info1.height;
290 GLsizei depth = info1.depth;
291 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
292 FaceIndexToGLTarget(ii);
293 int num_mips =
294 TextureManager::ComputeMipMapCount(target_, width, height, depth);
295 for (int level = 1; level < num_mips; ++level) {
296 width = std::max(1, width >> 1);
297 height = std::max(1, height >> 1);
298 depth = std::max(1, depth >> 1);
299 SetLevelInfo(feature_info,
300 target,
301 level,
302 info1.internal_format,
303 width,
304 height,
305 depth,
306 info1.border,
307 info1.format,
308 info1.type,
309 true);
310 }
311 }
312
313 return true;
314 }
315
SetTarget(const FeatureInfo * feature_info,GLenum target,GLint max_levels)316 void Texture::SetTarget(
317 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
318 DCHECK_EQ(0u, target_); // you can only set this once.
319 target_ = target;
320 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
321 level_infos_.resize(num_faces);
322 for (size_t ii = 0; ii < num_faces; ++ii) {
323 level_infos_[ii].resize(max_levels);
324 }
325
326 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
327 min_filter_ = GL_LINEAR;
328 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
329 }
330
331 if (target == GL_TEXTURE_EXTERNAL_OES) {
332 immutable_ = true;
333 }
334 Update(feature_info);
335 UpdateCanRenderCondition();
336 }
337
CanGenerateMipmaps(const FeatureInfo * feature_info) const338 bool Texture::CanGenerateMipmaps(
339 const FeatureInfo* feature_info) const {
340 if ((npot() && !feature_info->feature_flags().npot_ok) ||
341 level_infos_.empty() ||
342 target_ == GL_TEXTURE_EXTERNAL_OES ||
343 target_ == GL_TEXTURE_RECTANGLE_ARB) {
344 return false;
345 }
346
347 // Can't generate mips for depth or stencil textures.
348 const Texture::LevelInfo& first = level_infos_[0][0];
349 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
350 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
351 return false;
352 }
353
354 // TODO(gman): Check internal_format, format and type.
355 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
356 const LevelInfo& info = level_infos_[ii][0];
357 if ((info.target == 0) || (info.width != first.width) ||
358 (info.height != first.height) || (info.depth != 1) ||
359 (info.format != first.format) ||
360 (info.internal_format != first.internal_format) ||
361 (info.type != first.type) ||
362 feature_info->validators()->compressed_texture_format.IsValid(
363 info.internal_format) ||
364 info.image.get()) {
365 return false;
366 }
367 }
368 return true;
369 }
370
SetLevelCleared(GLenum target,GLint level,bool cleared)371 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
372 DCHECK_GE(level, 0);
373 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
374 level_infos_.size());
375 DCHECK_LT(static_cast<size_t>(level),
376 level_infos_[GLTargetToFaceIndex(target)].size());
377 Texture::LevelInfo& info =
378 level_infos_[GLTargetToFaceIndex(target)][level];
379 UpdateMipCleared(&info, cleared);
380 UpdateCleared();
381 }
382
UpdateCleared()383 void Texture::UpdateCleared() {
384 if (level_infos_.empty()) {
385 return;
386 }
387
388 const Texture::LevelInfo& first_face = level_infos_[0][0];
389 int levels_needed = TextureManager::ComputeMipMapCount(
390 target_, first_face.width, first_face.height, first_face.depth);
391 bool cleared = true;
392 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
393 for (GLint jj = 0; jj < levels_needed; ++jj) {
394 const Texture::LevelInfo& info = level_infos_[ii][jj];
395 if (info.width > 0 && info.height > 0 && info.depth > 0 &&
396 !info.cleared) {
397 cleared = false;
398 break;
399 }
400 }
401 }
402
403 // If texture is uncleared and is attached to a framebuffer,
404 // that framebuffer must be marked possibly incomplete.
405 if (!cleared && IsAttachedToFramebuffer()) {
406 IncAllFramebufferStateChangeCount();
407 }
408
409 UpdateSafeToRenderFrom(cleared);
410 }
411
UpdateSafeToRenderFrom(bool cleared)412 void Texture::UpdateSafeToRenderFrom(bool cleared) {
413 if (cleared_ == cleared)
414 return;
415 cleared_ = cleared;
416 int delta = cleared ? -1 : +1;
417 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
418 (*it)->manager()->UpdateSafeToRenderFrom(delta);
419 }
420
UpdateMipCleared(LevelInfo * info,bool cleared)421 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
422 if (info->cleared == cleared)
423 return;
424 info->cleared = cleared;
425 int delta = cleared ? -1 : +1;
426 num_uncleared_mips_ += delta;
427 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
428 (*it)->manager()->UpdateUnclearedMips(delta);
429 }
430
UpdateCanRenderCondition()431 void Texture::UpdateCanRenderCondition() {
432 CanRenderCondition can_render_condition = GetCanRenderCondition();
433 if (can_render_condition_ == can_render_condition)
434 return;
435 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
436 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
437 can_render_condition);
438 can_render_condition_ = can_render_condition;
439 }
440
UpdateHasImages()441 void Texture::UpdateHasImages() {
442 if (level_infos_.empty())
443 return;
444
445 bool has_images = false;
446 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
447 for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) {
448 const Texture::LevelInfo& info = level_infos_[ii][jj];
449 if (info.image.get() != NULL) {
450 has_images = true;
451 break;
452 }
453 }
454 }
455
456 if (has_images_ == has_images)
457 return;
458 has_images_ = has_images;
459 int delta = has_images ? +1 : -1;
460 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
461 (*it)->manager()->UpdateNumImages(delta);
462 }
463
IncAllFramebufferStateChangeCount()464 void Texture::IncAllFramebufferStateChangeCount() {
465 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
466 (*it)->manager()->IncFramebufferStateChangeCount();
467 }
468
SetLevelInfo(const FeatureInfo * feature_info,GLenum target,GLint level,GLenum internal_format,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,bool cleared)469 void Texture::SetLevelInfo(
470 const FeatureInfo* feature_info,
471 GLenum target,
472 GLint level,
473 GLenum internal_format,
474 GLsizei width,
475 GLsizei height,
476 GLsizei depth,
477 GLint border,
478 GLenum format,
479 GLenum type,
480 bool cleared) {
481 DCHECK_GE(level, 0);
482 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
483 level_infos_.size());
484 DCHECK_LT(static_cast<size_t>(level),
485 level_infos_[GLTargetToFaceIndex(target)].size());
486 DCHECK_GE(width, 0);
487 DCHECK_GE(height, 0);
488 DCHECK_GE(depth, 0);
489 Texture::LevelInfo& info =
490 level_infos_[GLTargetToFaceIndex(target)][level];
491 info.target = target;
492 info.level = level;
493 info.internal_format = internal_format;
494 info.width = width;
495 info.height = height;
496 info.depth = depth;
497 info.border = border;
498 info.format = format;
499 info.type = type;
500 info.image = 0;
501
502 estimated_size_ -= info.estimated_size;
503 GLES2Util::ComputeImageDataSizes(
504 width, height, format, type, 4, &info.estimated_size, NULL, NULL);
505 estimated_size_ += info.estimated_size;
506
507 UpdateMipCleared(&info, cleared);
508 max_level_set_ = std::max(max_level_set_, level);
509 Update(feature_info);
510 UpdateCleared();
511 UpdateCanRenderCondition();
512 UpdateHasImages();
513 if (IsAttachedToFramebuffer()) {
514 // TODO(gman): If textures tracked which framebuffers they were attached to
515 // we could just mark those framebuffers as not complete.
516 IncAllFramebufferStateChangeCount();
517 }
518 }
519
ValidForTexture(GLint target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum type) const520 bool Texture::ValidForTexture(
521 GLint target,
522 GLint level,
523 GLint xoffset,
524 GLint yoffset,
525 GLsizei width,
526 GLsizei height,
527 GLenum type) const {
528 size_t face_index = GLTargetToFaceIndex(target);
529 if (level >= 0 && face_index < level_infos_.size() &&
530 static_cast<size_t>(level) < level_infos_[face_index].size()) {
531 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
532 int32 right;
533 int32 top;
534 return SafeAddInt32(xoffset, width, &right) &&
535 SafeAddInt32(yoffset, height, &top) &&
536 xoffset >= 0 &&
537 yoffset >= 0 &&
538 right <= info.width &&
539 top <= info.height &&
540 type == info.type;
541 }
542 return false;
543 }
544
GetLevelSize(GLint target,GLint level,GLsizei * width,GLsizei * height) const545 bool Texture::GetLevelSize(
546 GLint target, GLint level, GLsizei* width, GLsizei* height) const {
547 DCHECK(width);
548 DCHECK(height);
549 size_t face_index = GLTargetToFaceIndex(target);
550 if (level >= 0 && face_index < level_infos_.size() &&
551 static_cast<size_t>(level) < level_infos_[face_index].size()) {
552 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
553 if (info.target != 0) {
554 *width = info.width;
555 *height = info.height;
556 return true;
557 }
558 }
559 return false;
560 }
561
GetLevelType(GLint target,GLint level,GLenum * type,GLenum * internal_format) const562 bool Texture::GetLevelType(
563 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
564 DCHECK(type);
565 DCHECK(internal_format);
566 size_t face_index = GLTargetToFaceIndex(target);
567 if (level >= 0 && face_index < level_infos_.size() &&
568 static_cast<size_t>(level) < level_infos_[face_index].size()) {
569 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
570 if (info.target != 0) {
571 *type = info.type;
572 *internal_format = info.internal_format;
573 return true;
574 }
575 }
576 return false;
577 }
578
SetParameteri(const FeatureInfo * feature_info,GLenum pname,GLint param)579 GLenum Texture::SetParameteri(
580 const FeatureInfo* feature_info, GLenum pname, GLint param) {
581 DCHECK(feature_info);
582
583 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
584 target_ == GL_TEXTURE_RECTANGLE_ARB) {
585 if (pname == GL_TEXTURE_MIN_FILTER &&
586 (param != GL_NEAREST && param != GL_LINEAR))
587 return GL_INVALID_ENUM;
588 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
589 param != GL_CLAMP_TO_EDGE)
590 return GL_INVALID_ENUM;
591 }
592
593 switch (pname) {
594 case GL_TEXTURE_MIN_FILTER:
595 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
596 return GL_INVALID_ENUM;
597 }
598 min_filter_ = param;
599 break;
600 case GL_TEXTURE_MAG_FILTER:
601 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
602 return GL_INVALID_ENUM;
603 }
604 mag_filter_ = param;
605 break;
606 case GL_TEXTURE_POOL_CHROMIUM:
607 if (!feature_info->validators()->texture_pool.IsValid(param)) {
608 return GL_INVALID_ENUM;
609 }
610 GetMemTracker()->TrackMemFree(estimated_size());
611 pool_ = param;
612 GetMemTracker()->TrackMemAlloc(estimated_size());
613 break;
614 case GL_TEXTURE_WRAP_S:
615 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
616 return GL_INVALID_ENUM;
617 }
618 wrap_s_ = param;
619 break;
620 case GL_TEXTURE_WRAP_T:
621 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
622 return GL_INVALID_ENUM;
623 }
624 wrap_t_ = param;
625 break;
626 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
627 if (param < 1) {
628 return GL_INVALID_VALUE;
629 }
630 break;
631 case GL_TEXTURE_USAGE_ANGLE:
632 if (!feature_info->validators()->texture_usage.IsValid(param)) {
633 return GL_INVALID_ENUM;
634 }
635 usage_ = param;
636 break;
637 default:
638 NOTREACHED();
639 return GL_INVALID_ENUM;
640 }
641 Update(feature_info);
642 UpdateCleared();
643 UpdateCanRenderCondition();
644 return GL_NO_ERROR;
645 }
646
SetParameterf(const FeatureInfo * feature_info,GLenum pname,GLfloat param)647 GLenum Texture::SetParameterf(
648 const FeatureInfo* feature_info, GLenum pname, GLfloat param) {
649 switch (pname) {
650 case GL_TEXTURE_MIN_FILTER:
651 case GL_TEXTURE_MAG_FILTER:
652 case GL_TEXTURE_POOL_CHROMIUM:
653 case GL_TEXTURE_WRAP_S:
654 case GL_TEXTURE_WRAP_T:
655 case GL_TEXTURE_USAGE_ANGLE:
656 {
657 GLint iparam = static_cast<GLint>(param);
658 return SetParameteri(feature_info, pname, iparam);
659 }
660 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
661 if (param < 1.f) {
662 return GL_INVALID_VALUE;
663 }
664 break;
665 default:
666 NOTREACHED();
667 return GL_INVALID_ENUM;
668 }
669 return GL_NO_ERROR;
670 }
671
Update(const FeatureInfo * feature_info)672 void Texture::Update(const FeatureInfo* feature_info) {
673 // Update npot status.
674 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
675 npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
676
677 if (level_infos_.empty()) {
678 texture_complete_ = false;
679 cube_complete_ = false;
680 return;
681 }
682
683 // checks that the first mip of any face is npot.
684 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
685 const Texture::LevelInfo& info = level_infos_[ii][0];
686 if (GLES2Util::IsNPOT(info.width) ||
687 GLES2Util::IsNPOT(info.height) ||
688 GLES2Util::IsNPOT(info.depth)) {
689 npot_ = true;
690 break;
691 }
692 }
693
694 // Update texture_complete and cube_complete status.
695 const Texture::LevelInfo& first_face = level_infos_[0][0];
696 int levels_needed = TextureManager::ComputeMipMapCount(
697 target_, first_face.width, first_face.height, first_face.depth);
698 texture_complete_ =
699 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
700 cube_complete_ = (level_infos_.size() == 6) &&
701 (first_face.width == first_face.height);
702
703 if (first_face.width == 0 || first_face.height == 0) {
704 texture_complete_ = false;
705 }
706 if (first_face.type == GL_FLOAT &&
707 !feature_info->feature_flags().enable_texture_float_linear &&
708 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
709 mag_filter_ != GL_NEAREST)) {
710 texture_complete_ = false;
711 } else if (first_face.type == GL_HALF_FLOAT_OES &&
712 !feature_info->feature_flags().enable_texture_half_float_linear &&
713 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
714 mag_filter_ != GL_NEAREST)) {
715 texture_complete_ = false;
716 }
717 for (size_t ii = 0;
718 ii < level_infos_.size() && (cube_complete_ || texture_complete_);
719 ++ii) {
720 const Texture::LevelInfo& level0 = level_infos_[ii][0];
721 if (level0.target == 0 ||
722 level0.width != first_face.width ||
723 level0.height != first_face.height ||
724 level0.depth != 1 ||
725 level0.internal_format != first_face.internal_format ||
726 level0.format != first_face.format ||
727 level0.type != first_face.type) {
728 cube_complete_ = false;
729 }
730 // Get level0 dimensions
731 GLsizei width = level0.width;
732 GLsizei height = level0.height;
733 GLsizei depth = level0.depth;
734 for (GLint jj = 1; jj < levels_needed; ++jj) {
735 // compute required size for mip.
736 width = std::max(1, width >> 1);
737 height = std::max(1, height >> 1);
738 depth = std::max(1, depth >> 1);
739 const Texture::LevelInfo& info = level_infos_[ii][jj];
740 if (info.target == 0 ||
741 info.width != width ||
742 info.height != height ||
743 info.depth != depth ||
744 info.internal_format != level0.internal_format ||
745 info.format != level0.format ||
746 info.type != level0.type) {
747 texture_complete_ = false;
748 break;
749 }
750 }
751 }
752 }
753
ClearRenderableLevels(GLES2Decoder * decoder)754 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
755 DCHECK(decoder);
756 if (cleared_) {
757 return true;
758 }
759
760 const Texture::LevelInfo& first_face = level_infos_[0][0];
761 int levels_needed = TextureManager::ComputeMipMapCount(
762 target_, first_face.width, first_face.height, first_face.depth);
763
764 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
765 for (GLint jj = 0; jj < levels_needed; ++jj) {
766 Texture::LevelInfo& info = level_infos_[ii][jj];
767 if (info.target != 0) {
768 if (!ClearLevel(decoder, info.target, jj)) {
769 return false;
770 }
771 }
772 }
773 }
774 UpdateSafeToRenderFrom(true);
775 return true;
776 }
777
IsLevelCleared(GLenum target,GLint level) const778 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
779 size_t face_index = GLTargetToFaceIndex(target);
780 if (face_index >= level_infos_.size() ||
781 level >= static_cast<GLint>(level_infos_[face_index].size())) {
782 return true;
783 }
784
785 const Texture::LevelInfo& info = level_infos_[face_index][level];
786
787 return info.cleared;
788 }
789
InitTextureMaxAnisotropyIfNeeded(GLenum target)790 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
791 if (texture_max_anisotropy_initialized_)
792 return;
793 texture_max_anisotropy_initialized_ = true;
794 GLfloat params[] = { 1.0f };
795 glTexParameterfv(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params);
796 }
797
ClearLevel(GLES2Decoder * decoder,GLenum target,GLint level)798 bool Texture::ClearLevel(
799 GLES2Decoder* decoder, GLenum target, GLint level) {
800 DCHECK(decoder);
801 size_t face_index = GLTargetToFaceIndex(target);
802 if (face_index >= level_infos_.size() ||
803 level >= static_cast<GLint>(level_infos_[face_index].size())) {
804 return true;
805 }
806
807 Texture::LevelInfo& info = level_infos_[face_index][level];
808
809 DCHECK(target == info.target);
810
811 if (info.target == 0 ||
812 info.cleared ||
813 info.width == 0 ||
814 info.height == 0 ||
815 info.depth == 0) {
816 return true;
817 }
818
819 // NOTE: It seems kind of gross to call back into the decoder for this
820 // but only the decoder knows all the state (like unpack_alignment_) that's
821 // needed to be able to call GL correctly.
822 bool cleared = decoder->ClearLevel(
823 service_id_, target_, info.target, info.level, info.internal_format,
824 info.format, info.type, info.width, info.height, immutable_);
825 UpdateMipCleared(&info, cleared);
826 return info.cleared;
827 }
828
SetLevelImage(const FeatureInfo * feature_info,GLenum target,GLint level,gfx::GLImage * image)829 void Texture::SetLevelImage(
830 const FeatureInfo* feature_info,
831 GLenum target,
832 GLint level,
833 gfx::GLImage* image) {
834 DCHECK_GE(level, 0);
835 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
836 level_infos_.size());
837 DCHECK_LT(static_cast<size_t>(level),
838 level_infos_[GLTargetToFaceIndex(target)].size());
839 Texture::LevelInfo& info =
840 level_infos_[GLTargetToFaceIndex(target)][level];
841 DCHECK_EQ(info.target, target);
842 DCHECK_EQ(info.level, level);
843 info.image = image;
844 UpdateCanRenderCondition();
845 UpdateHasImages();
846 }
847
GetLevelImage(GLint target,GLint level) const848 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
849 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
850 target != GL_TEXTURE_RECTANGLE_ARB) {
851 return NULL;
852 }
853
854 size_t face_index = GLTargetToFaceIndex(target);
855 if (level >= 0 && face_index < level_infos_.size() &&
856 static_cast<size_t>(level) < level_infos_[face_index].size()) {
857 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
858 if (info.target != 0) {
859 return info.image.get();
860 }
861 }
862 return 0;
863 }
864
OnWillModifyPixels()865 void Texture::OnWillModifyPixels() {
866 gfx::GLImage* image = GetLevelImage(target(), 0);
867 if (image)
868 image->WillModifyTexImage();
869 }
870
OnDidModifyPixels()871 void Texture::OnDidModifyPixels() {
872 gfx::GLImage* image = GetLevelImage(target(), 0);
873 if (image)
874 image->DidModifyTexImage();
875 }
876
TextureRef(TextureManager * manager,GLuint client_id,Texture * texture)877 TextureRef::TextureRef(TextureManager* manager,
878 GLuint client_id,
879 Texture* texture)
880 : manager_(manager),
881 texture_(texture),
882 client_id_(client_id),
883 num_observers_(0) {
884 DCHECK(manager_);
885 DCHECK(texture_);
886 texture_->AddTextureRef(this);
887 manager_->StartTracking(this);
888 }
889
Create(TextureManager * manager,GLuint client_id,GLuint service_id)890 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
891 GLuint client_id,
892 GLuint service_id) {
893 return new TextureRef(manager, client_id, new Texture(service_id));
894 }
895
~TextureRef()896 TextureRef::~TextureRef() {
897 manager_->StopTracking(this);
898 texture_->RemoveTextureRef(this, manager_->have_context_);
899 manager_ = NULL;
900 }
901
TextureManager(MemoryTracker * memory_tracker,FeatureInfo * feature_info,GLint max_texture_size,GLint max_cube_map_texture_size,bool use_default_textures)902 TextureManager::TextureManager(MemoryTracker* memory_tracker,
903 FeatureInfo* feature_info,
904 GLint max_texture_size,
905 GLint max_cube_map_texture_size,
906 bool use_default_textures)
907 : memory_tracker_managed_(
908 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
909 memory_tracker_unmanaged_(
910 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
911 feature_info_(feature_info),
912 framebuffer_manager_(NULL),
913 max_texture_size_(max_texture_size),
914 max_cube_map_texture_size_(max_cube_map_texture_size),
915 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
916 max_texture_size,
917 max_texture_size,
918 max_texture_size)),
919 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
920 max_cube_map_texture_size,
921 max_cube_map_texture_size,
922 max_cube_map_texture_size)),
923 use_default_textures_(use_default_textures),
924 num_unrenderable_textures_(0),
925 num_unsafe_textures_(0),
926 num_uncleared_mips_(0),
927 num_images_(0),
928 texture_count_(0),
929 have_context_(true) {
930 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
931 black_texture_ids_[ii] = 0;
932 }
933 }
934
Initialize()935 bool TextureManager::Initialize() {
936 // TODO(gman): The default textures have to be real textures, not the 0
937 // texture because we simulate non shared resources on top of shared
938 // resources and all contexts that share resource share the same default
939 // texture.
940 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
941 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
942 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
943 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
944
945 if (feature_info_->feature_flags().oes_egl_image_external) {
946 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
947 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
948 }
949
950 if (feature_info_->feature_flags().arb_texture_rectangle) {
951 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
952 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
953 }
954
955 return true;
956 }
957
958 scoped_refptr<TextureRef>
CreateDefaultAndBlackTextures(GLenum target,GLuint * black_texture)959 TextureManager::CreateDefaultAndBlackTextures(
960 GLenum target,
961 GLuint* black_texture) {
962 static uint8 black[] = {0, 0, 0, 255};
963
964 // Sampling a texture not associated with any EGLImage sibling will return
965 // black values according to the spec.
966 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
967 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
968
969 // Make default textures and texture for replacing non-renderable textures.
970 GLuint ids[2];
971 const unsigned long num_ids = use_default_textures_ ? 2 : 1;
972 glGenTextures(num_ids, ids);
973 for (unsigned long ii = 0; ii < num_ids; ++ii) {
974 glBindTexture(target, ids[ii]);
975 if (needs_initialization) {
976 if (needs_faces) {
977 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
978 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
979 GL_RGBA, GL_UNSIGNED_BYTE, black);
980 }
981 } else {
982 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
983 GL_UNSIGNED_BYTE, black);
984 }
985 }
986 }
987 glBindTexture(target, 0);
988
989 scoped_refptr<TextureRef> default_texture;
990 if (use_default_textures_) {
991 default_texture = TextureRef::Create(this, 0, ids[1]);
992 SetTarget(default_texture.get(), target);
993 if (needs_faces) {
994 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
995 SetLevelInfo(default_texture.get(),
996 GLES2Util::IndexToGLFaceTarget(ii),
997 0,
998 GL_RGBA,
999 1,
1000 1,
1001 1,
1002 0,
1003 GL_RGBA,
1004 GL_UNSIGNED_BYTE,
1005 true);
1006 }
1007 } else {
1008 if (needs_initialization) {
1009 SetLevelInfo(default_texture.get(),
1010 GL_TEXTURE_2D,
1011 0,
1012 GL_RGBA,
1013 1,
1014 1,
1015 1,
1016 0,
1017 GL_RGBA,
1018 GL_UNSIGNED_BYTE,
1019 true);
1020 } else {
1021 SetLevelInfo(default_texture.get(),
1022 GL_TEXTURE_EXTERNAL_OES,
1023 0,
1024 GL_RGBA,
1025 1,
1026 1,
1027 1,
1028 0,
1029 GL_RGBA,
1030 GL_UNSIGNED_BYTE,
1031 true);
1032 }
1033 }
1034 }
1035
1036 *black_texture = ids[0];
1037 return default_texture;
1038 }
1039
ValidForTarget(GLenum target,GLint level,GLsizei width,GLsizei height,GLsizei depth)1040 bool TextureManager::ValidForTarget(
1041 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
1042 GLsizei max_size = MaxSizeForTarget(target) >> level;
1043 return level >= 0 &&
1044 width >= 0 &&
1045 height >= 0 &&
1046 depth >= 0 &&
1047 level < MaxLevelsForTarget(target) &&
1048 width <= max_size &&
1049 height <= max_size &&
1050 depth <= max_size &&
1051 (level == 0 || feature_info_->feature_flags().npot_ok ||
1052 (!GLES2Util::IsNPOT(width) &&
1053 !GLES2Util::IsNPOT(height) &&
1054 !GLES2Util::IsNPOT(depth))) &&
1055 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1056 (target != GL_TEXTURE_2D || (depth == 1));
1057 }
1058
SetTarget(TextureRef * ref,GLenum target)1059 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1060 DCHECK(ref);
1061 ref->texture()
1062 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1063 }
1064
SetLevelCleared(TextureRef * ref,GLenum target,GLint level,bool cleared)1065 void TextureManager::SetLevelCleared(TextureRef* ref,
1066 GLenum target,
1067 GLint level,
1068 bool cleared) {
1069 DCHECK(ref);
1070 ref->texture()->SetLevelCleared(target, level, cleared);
1071 }
1072
ClearRenderableLevels(GLES2Decoder * decoder,TextureRef * ref)1073 bool TextureManager::ClearRenderableLevels(
1074 GLES2Decoder* decoder, TextureRef* ref) {
1075 DCHECK(ref);
1076 return ref->texture()->ClearRenderableLevels(decoder);
1077 }
1078
ClearTextureLevel(GLES2Decoder * decoder,TextureRef * ref,GLenum target,GLint level)1079 bool TextureManager::ClearTextureLevel(
1080 GLES2Decoder* decoder, TextureRef* ref,
1081 GLenum target, GLint level) {
1082 DCHECK(ref);
1083 Texture* texture = ref->texture();
1084 if (texture->num_uncleared_mips() == 0) {
1085 return true;
1086 }
1087 bool result = texture->ClearLevel(decoder, target, level);
1088 texture->UpdateCleared();
1089 return result;
1090 }
1091
SetLevelInfo(TextureRef * ref,GLenum target,GLint level,GLenum internal_format,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,bool cleared)1092 void TextureManager::SetLevelInfo(
1093 TextureRef* ref,
1094 GLenum target,
1095 GLint level,
1096 GLenum internal_format,
1097 GLsizei width,
1098 GLsizei height,
1099 GLsizei depth,
1100 GLint border,
1101 GLenum format,
1102 GLenum type,
1103 bool cleared) {
1104 DCHECK(ref);
1105 Texture* texture = ref->texture();
1106
1107 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1108 texture->SetLevelInfo(feature_info_.get(),
1109 target,
1110 level,
1111 internal_format,
1112 width,
1113 height,
1114 depth,
1115 border,
1116 format,
1117 type,
1118 cleared);
1119 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1120 }
1121
Produce(TextureRef * ref)1122 Texture* TextureManager::Produce(TextureRef* ref) {
1123 DCHECK(ref);
1124 return ref->texture();
1125 }
1126
Consume(GLuint client_id,Texture * texture)1127 TextureRef* TextureManager::Consume(
1128 GLuint client_id,
1129 Texture* texture) {
1130 DCHECK(client_id);
1131 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1132 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1133 DCHECK(result);
1134 return ref.get();
1135 }
1136
SetParameteri(const char * function_name,ErrorState * error_state,TextureRef * ref,GLenum pname,GLint param)1137 void TextureManager::SetParameteri(
1138 const char* function_name, ErrorState* error_state,
1139 TextureRef* ref, GLenum pname, GLint param) {
1140 DCHECK(error_state);
1141 DCHECK(ref);
1142 Texture* texture = ref->texture();
1143 GLenum result = texture->SetParameteri(feature_info_.get(), pname, param);
1144 if (result != GL_NO_ERROR) {
1145 if (result == GL_INVALID_ENUM) {
1146 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1147 error_state, function_name, param, "param");
1148 } else {
1149 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1150 error_state, result, function_name, pname, param);
1151 }
1152 } else {
1153 // Texture tracking pools exist only for the command decoder, so
1154 // do not pass them on to the native GL implementation.
1155 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1156 glTexParameteri(texture->target(), pname, param);
1157 }
1158 }
1159 }
1160
SetParameterf(const char * function_name,ErrorState * error_state,TextureRef * ref,GLenum pname,GLfloat param)1161 void TextureManager::SetParameterf(
1162 const char* function_name, ErrorState* error_state,
1163 TextureRef* ref, GLenum pname, GLfloat param) {
1164 DCHECK(error_state);
1165 DCHECK(ref);
1166 Texture* texture = ref->texture();
1167 GLenum result = texture->SetParameterf(feature_info_.get(), pname, param);
1168 if (result != GL_NO_ERROR) {
1169 if (result == GL_INVALID_ENUM) {
1170 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1171 error_state, function_name, param, "param");
1172 } else {
1173 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1174 error_state, result, function_name, pname, param);
1175 }
1176 } else {
1177 // Texture tracking pools exist only for the command decoder, so
1178 // do not pass them on to the native GL implementation.
1179 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1180 glTexParameterf(texture->target(), pname, param);
1181 }
1182 }
1183 }
1184
MarkMipmapsGenerated(TextureRef * ref)1185 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1186 DCHECK(ref);
1187 Texture* texture = ref->texture();
1188 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1189 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1190 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1191 return result;
1192 }
1193
CreateTexture(GLuint client_id,GLuint service_id)1194 TextureRef* TextureManager::CreateTexture(
1195 GLuint client_id, GLuint service_id) {
1196 DCHECK_NE(0u, service_id);
1197 scoped_refptr<TextureRef> ref(TextureRef::Create(
1198 this, client_id, service_id));
1199 std::pair<TextureMap::iterator, bool> result =
1200 textures_.insert(std::make_pair(client_id, ref));
1201 DCHECK(result.second);
1202 return ref.get();
1203 }
1204
GetTexture(GLuint client_id) const1205 TextureRef* TextureManager::GetTexture(
1206 GLuint client_id) const {
1207 TextureMap::const_iterator it = textures_.find(client_id);
1208 return it != textures_.end() ? it->second.get() : NULL;
1209 }
1210
RemoveTexture(GLuint client_id)1211 void TextureManager::RemoveTexture(GLuint client_id) {
1212 TextureMap::iterator it = textures_.find(client_id);
1213 if (it != textures_.end()) {
1214 it->second->reset_client_id();
1215 textures_.erase(it);
1216 }
1217 }
1218
StartTracking(TextureRef * ref)1219 void TextureManager::StartTracking(TextureRef* ref) {
1220 Texture* texture = ref->texture();
1221 ++texture_count_;
1222 num_uncleared_mips_ += texture->num_uncleared_mips();
1223 if (!texture->SafeToRenderFrom())
1224 ++num_unsafe_textures_;
1225 if (!texture->CanRender(feature_info_.get()))
1226 ++num_unrenderable_textures_;
1227 if (texture->HasImages())
1228 ++num_images_;
1229 }
1230
StopTracking(TextureRef * ref)1231 void TextureManager::StopTracking(TextureRef* ref) {
1232 if (ref->num_observers()) {
1233 for (unsigned int i = 0; i < destruction_observers_.size(); i++) {
1234 destruction_observers_[i]->OnTextureRefDestroying(ref);
1235 }
1236 DCHECK_EQ(ref->num_observers(), 0);
1237 }
1238
1239 Texture* texture = ref->texture();
1240
1241 --texture_count_;
1242 if (texture->HasImages()) {
1243 DCHECK_NE(0, num_images_);
1244 --num_images_;
1245 }
1246 if (!texture->CanRender(feature_info_.get())) {
1247 DCHECK_NE(0, num_unrenderable_textures_);
1248 --num_unrenderable_textures_;
1249 }
1250 if (!texture->SafeToRenderFrom()) {
1251 DCHECK_NE(0, num_unsafe_textures_);
1252 --num_unsafe_textures_;
1253 }
1254 num_uncleared_mips_ -= texture->num_uncleared_mips();
1255 DCHECK_GE(num_uncleared_mips_, 0);
1256 }
1257
GetMemTracker(GLenum tracking_pool)1258 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1259 switch(tracking_pool) {
1260 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1261 return memory_tracker_managed_.get();
1262 break;
1263 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1264 return memory_tracker_unmanaged_.get();
1265 break;
1266 default:
1267 break;
1268 }
1269 NOTREACHED();
1270 return NULL;
1271 }
1272
GetTextureForServiceId(GLuint service_id) const1273 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1274 // This doesn't need to be fast. It's only used during slow queries.
1275 for (TextureMap::const_iterator it = textures_.begin();
1276 it != textures_.end(); ++it) {
1277 Texture* texture = it->second->texture();
1278 if (texture->service_id() == service_id)
1279 return texture;
1280 }
1281 return NULL;
1282 }
1283
ComputeMipMapCount(GLenum target,GLsizei width,GLsizei height,GLsizei depth)1284 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1285 GLsizei width,
1286 GLsizei height,
1287 GLsizei depth) {
1288 switch (target) {
1289 case GL_TEXTURE_EXTERNAL_OES:
1290 return 1;
1291 default:
1292 return 1 +
1293 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1294 }
1295 }
1296
SetLevelImage(TextureRef * ref,GLenum target,GLint level,gfx::GLImage * image)1297 void TextureManager::SetLevelImage(
1298 TextureRef* ref,
1299 GLenum target,
1300 GLint level,
1301 gfx::GLImage* image) {
1302 DCHECK(ref);
1303 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1304 }
1305
AddToSignature(TextureRef * ref,GLenum target,GLint level,std::string * signature) const1306 void TextureManager::AddToSignature(
1307 TextureRef* ref,
1308 GLenum target,
1309 GLint level,
1310 std::string* signature) const {
1311 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1312 }
1313
UpdateSafeToRenderFrom(int delta)1314 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1315 num_unsafe_textures_ += delta;
1316 DCHECK_GE(num_unsafe_textures_, 0);
1317 }
1318
UpdateUnclearedMips(int delta)1319 void TextureManager::UpdateUnclearedMips(int delta) {
1320 num_uncleared_mips_ += delta;
1321 DCHECK_GE(num_uncleared_mips_, 0);
1322 }
1323
UpdateCanRenderCondition(Texture::CanRenderCondition old_condition,Texture::CanRenderCondition new_condition)1324 void TextureManager::UpdateCanRenderCondition(
1325 Texture::CanRenderCondition old_condition,
1326 Texture::CanRenderCondition new_condition) {
1327 if (old_condition == Texture::CAN_RENDER_NEVER ||
1328 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1329 !feature_info_->feature_flags().npot_ok)) {
1330 DCHECK_GT(num_unrenderable_textures_, 0);
1331 --num_unrenderable_textures_;
1332 }
1333 if (new_condition == Texture::CAN_RENDER_NEVER ||
1334 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1335 !feature_info_->feature_flags().npot_ok))
1336 ++num_unrenderable_textures_;
1337 }
1338
UpdateNumImages(int delta)1339 void TextureManager::UpdateNumImages(int delta) {
1340 num_images_ += delta;
1341 DCHECK_GE(num_images_, 0);
1342 }
1343
IncFramebufferStateChangeCount()1344 void TextureManager::IncFramebufferStateChangeCount() {
1345 if (framebuffer_manager_)
1346 framebuffer_manager_->IncFramebufferStateChangeCount();
1347 }
1348
ValidateFormatAndTypeCombination(ErrorState * error_state,const char * function_name,GLenum format,GLenum type)1349 bool TextureManager::ValidateFormatAndTypeCombination(
1350 ErrorState* error_state, const char* function_name, GLenum format,
1351 GLenum type) {
1352 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1353 ERRORSTATE_SET_GL_ERROR(
1354 error_state, GL_INVALID_OPERATION, function_name,
1355 (std::string("invalid type ") +
1356 GLES2Util::GetStringEnum(type) + " for format " +
1357 GLES2Util::GetStringEnum(format)).c_str());
1358 return false;
1359 }
1360 return true;
1361 }
1362
ValidateTextureParameters(ErrorState * error_state,const char * function_name,GLenum format,GLenum type,GLenum internal_format,GLint level)1363 bool TextureManager::ValidateTextureParameters(
1364 ErrorState* error_state, const char* function_name,
1365 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1366 const Validators* validators = feature_info_->validators();
1367 if (!validators->texture_format.IsValid(format)) {
1368 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1369 error_state, function_name, format, "format");
1370 return false;
1371 }
1372 if (!validators->pixel_type.IsValid(type)) {
1373 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1374 error_state, function_name, type, "type");
1375 return false;
1376 }
1377 if (format != internal_format &&
1378 !((internal_format == GL_RGBA32F && format == GL_RGBA) ||
1379 (internal_format == GL_RGB32F && format == GL_RGB))) {
1380 ERRORSTATE_SET_GL_ERROR(
1381 error_state, GL_INVALID_OPERATION, function_name,
1382 "format != internalformat");
1383 return false;
1384 }
1385 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1386 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1387 ERRORSTATE_SET_GL_ERROR(
1388 error_state, GL_INVALID_OPERATION, function_name,
1389 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1390 " for level != 0").c_str());
1391 return false;
1392 }
1393 return ValidateFormatAndTypeCombination(error_state, function_name,
1394 format, type);
1395 }
1396
1397 // Gets the texture id for a given target.
GetTextureInfoForTarget(ContextState * state,GLenum target)1398 TextureRef* TextureManager::GetTextureInfoForTarget(
1399 ContextState* state, GLenum target) {
1400 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1401 TextureRef* texture = NULL;
1402 switch (target) {
1403 case GL_TEXTURE_2D:
1404 texture = unit.bound_texture_2d.get();
1405 break;
1406 case GL_TEXTURE_CUBE_MAP:
1407 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1408 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1409 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1410 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1411 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1412 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1413 texture = unit.bound_texture_cube_map.get();
1414 break;
1415 case GL_TEXTURE_EXTERNAL_OES:
1416 texture = unit.bound_texture_external_oes.get();
1417 break;
1418 case GL_TEXTURE_RECTANGLE_ARB:
1419 texture = unit.bound_texture_rectangle_arb.get();
1420 break;
1421 default:
1422 NOTREACHED();
1423 return NULL;
1424 }
1425 return texture;
1426 }
1427
GetTextureInfoForTargetUnlessDefault(ContextState * state,GLenum target)1428 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1429 ContextState* state, GLenum target) {
1430 TextureRef* texture = GetTextureInfoForTarget(state, target);
1431 if (!texture)
1432 return NULL;
1433 if (texture == GetDefaultTextureInfo(target))
1434 return NULL;
1435 return texture;
1436 }
1437
ValidateTexImage2D(ContextState * state,const char * function_name,const DoTextImage2DArguments & args,TextureRef ** texture_ref)1438 bool TextureManager::ValidateTexImage2D(
1439 ContextState* state,
1440 const char* function_name,
1441 const DoTextImage2DArguments& args,
1442 TextureRef** texture_ref) {
1443 ErrorState* error_state = state->GetErrorState();
1444 const Validators* validators = feature_info_->validators();
1445 if (!validators->texture_target.IsValid(args.target)) {
1446 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1447 error_state, function_name, args.target, "target");
1448 return false;
1449 }
1450 if (!validators->texture_internal_format.IsValid(args.internal_format)) {
1451 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1452 error_state, function_name, args.internal_format,
1453 "internalformat");
1454 return false;
1455 }
1456 if (!ValidateTextureParameters(
1457 error_state, function_name, args.format, args.type,
1458 args.internal_format, args.level)) {
1459 return false;
1460 }
1461 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1462 args.border != 0) {
1463 ERRORSTATE_SET_GL_ERROR(
1464 error_state, GL_INVALID_VALUE, function_name,
1465 "dimensions out of range");
1466 return false;
1467 }
1468 if ((GLES2Util::GetChannelsForFormat(args.format) &
1469 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1470 ERRORSTATE_SET_GL_ERROR(
1471 error_state, GL_INVALID_OPERATION,
1472 function_name, "can not supply data for depth or stencil textures");
1473 return false;
1474 }
1475
1476 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1477 if (!local_texture_ref) {
1478 ERRORSTATE_SET_GL_ERROR(
1479 error_state, GL_INVALID_OPERATION, function_name,
1480 "unknown texture for target");
1481 return false;
1482 }
1483 if (local_texture_ref->texture()->IsImmutable()) {
1484 ERRORSTATE_SET_GL_ERROR(
1485 error_state, GL_INVALID_OPERATION, function_name,
1486 "texture is immutable");
1487 return false;
1488 }
1489
1490 // TODO - verify that using the managed vs unmanaged does not matter.
1491 // They both use the same MemoryTracker, and this call just re-routes
1492 // to it.
1493 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1494 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1495 "out of memory");
1496 return false;
1497 }
1498
1499 // Write the TextureReference since this is valid.
1500 *texture_ref = local_texture_ref;
1501 return true;
1502 }
1503
ValidateAndDoTexImage2D(DecoderTextureState * texture_state,ContextState * state,DecoderFramebufferState * framebuffer_state,const DoTextImage2DArguments & args)1504 void TextureManager::ValidateAndDoTexImage2D(
1505 DecoderTextureState* texture_state,
1506 ContextState* state,
1507 DecoderFramebufferState* framebuffer_state,
1508 const DoTextImage2DArguments& args) {
1509 TextureRef* texture_ref;
1510 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1511 return;
1512 }
1513
1514 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1515 texture_ref, args);
1516 }
1517
DoTexImage2D(DecoderTextureState * texture_state,ErrorState * error_state,DecoderFramebufferState * framebuffer_state,TextureRef * texture_ref,const DoTextImage2DArguments & args)1518 void TextureManager::DoTexImage2D(
1519 DecoderTextureState* texture_state,
1520 ErrorState* error_state,
1521 DecoderFramebufferState* framebuffer_state,
1522 TextureRef* texture_ref,
1523 const DoTextImage2DArguments& args) {
1524 Texture* texture = texture_ref->texture();
1525 GLsizei tex_width = 0;
1526 GLsizei tex_height = 0;
1527 GLenum tex_type = 0;
1528 GLenum tex_format = 0;
1529 bool level_is_same =
1530 texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
1531 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1532 args.width == tex_width && args.height == tex_height &&
1533 args.type == tex_type && args.format == tex_format;
1534
1535 if (level_is_same && !args.pixels) {
1536 // Just set the level texture but mark the texture as uncleared.
1537 SetLevelInfo(
1538 texture_ref,
1539 args.target, args.level, args.internal_format, args.width, args.height,
1540 1, args.border, args.format, args.type, false);
1541 texture_state->tex_image_2d_failed = false;
1542 return;
1543 }
1544
1545 if (texture->IsAttachedToFramebuffer()) {
1546 framebuffer_state->clear_state_dirty = true;
1547 }
1548
1549 if (texture_state->texsubimage2d_faster_than_teximage2d &&
1550 level_is_same && args.pixels) {
1551 {
1552 ScopedTextureUploadTimer timer(texture_state);
1553 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1554 args.format, args.type, args.pixels);
1555 }
1556 SetLevelCleared(texture_ref, args.target, args.level, true);
1557 texture_state->tex_image_2d_failed = false;
1558 return;
1559 }
1560
1561 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1562 {
1563 ScopedTextureUploadTimer timer(texture_state);
1564 glTexImage2D(
1565 args.target, args.level, args.internal_format, args.width, args.height,
1566 args.border, args.format, args.type, args.pixels);
1567 }
1568 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1569 if (error == GL_NO_ERROR) {
1570 SetLevelInfo(
1571 texture_ref,
1572 args.target, args.level, args.internal_format, args.width, args.height,
1573 1, args.border, args.format, args.type, args.pixels != NULL);
1574 texture_state->tex_image_2d_failed = false;
1575 }
1576 }
1577
ScopedTextureUploadTimer(DecoderTextureState * texture_state)1578 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1579 DecoderTextureState* texture_state)
1580 : texture_state_(texture_state),
1581 begin_time_(base::TimeTicks::HighResNow()) {
1582 }
1583
~ScopedTextureUploadTimer()1584 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1585 texture_state_->texture_upload_count++;
1586 texture_state_->total_texture_upload_time +=
1587 base::TimeTicks::HighResNow() - begin_time_;
1588 }
1589
1590 } // namespace gles2
1591 } // namespace gpu
1592