1// Copyright 2013 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 "cc/test/test_web_graphics_context_3d.h"
6
7#include <algorithm>
8#include <string>
9
10#include "base/bind.h"
11#include "base/lazy_instance.h"
12#include "base/logging.h"
13#include "base/message_loop/message_loop.h"
14#include "cc/test/test_context_support.h"
15#include "gpu/GLES2/gl2extchromium.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "third_party/khronos/GLES2/gl2ext.h"
18
19namespace cc {
20
21static const GLuint kFramebufferId = 1;
22static const GLuint kRenderbufferId = 2;
23
24static unsigned s_context_id = 1;
25
26const GLuint TestWebGraphicsContext3D::kExternalTextureId = 1337;
27
28static base::LazyInstance<base::Lock>::Leaky
29    g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER;
30
31TestWebGraphicsContext3D::Namespace*
32    TestWebGraphicsContext3D::shared_namespace_ = NULL;
33
34TestWebGraphicsContext3D::Namespace::Namespace()
35    : next_buffer_id(1),
36      next_image_id(1),
37      next_texture_id(1) {
38}
39
40TestWebGraphicsContext3D::Namespace::~Namespace() {
41  g_shared_namespace_lock.Get().AssertAcquired();
42  if (shared_namespace_ == this)
43    shared_namespace_ = NULL;
44}
45
46// static
47scoped_ptr<TestWebGraphicsContext3D> TestWebGraphicsContext3D::Create() {
48  return make_scoped_ptr(new TestWebGraphicsContext3D());
49}
50
51TestWebGraphicsContext3D::TestWebGraphicsContext3D()
52    : context_id_(s_context_id++),
53      times_bind_texture_succeeds_(-1),
54      times_end_query_succeeds_(-1),
55      context_lost_(false),
56      times_map_image_chromium_succeeds_(-1),
57      times_map_buffer_chromium_succeeds_(-1),
58      current_used_transfer_buffer_usage_bytes_(0),
59      max_used_transfer_buffer_usage_bytes_(0),
60      next_program_id_(1000),
61      next_shader_id_(2000),
62      max_texture_size_(2048),
63      reshape_called_(false),
64      width_(0),
65      height_(0),
66      scale_factor_(-1.f),
67      test_support_(NULL),
68      last_update_type_(NoUpdate),
69      next_insert_sync_point_(1),
70      last_waited_sync_point_(0),
71      bound_buffer_(0),
72      weak_ptr_factory_(this) {
73  CreateNamespace();
74}
75
76TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
77  base::AutoLock lock(g_shared_namespace_lock.Get());
78  namespace_ = NULL;
79}
80
81void TestWebGraphicsContext3D::CreateNamespace() {
82  base::AutoLock lock(g_shared_namespace_lock.Get());
83  if (shared_namespace_) {
84    namespace_ = shared_namespace_;
85  } else {
86    namespace_ = new Namespace;
87    shared_namespace_ = namespace_.get();
88  }
89}
90
91void TestWebGraphicsContext3D::reshapeWithScaleFactor(
92    int width, int height, float scale_factor) {
93  reshape_called_ = true;
94  width_ = width;
95  height_ = height;
96  scale_factor_ = scale_factor;
97}
98
99bool TestWebGraphicsContext3D::isContextLost() {
100  return context_lost_;
101}
102
103GLenum TestWebGraphicsContext3D::checkFramebufferStatus(
104    GLenum target) {
105  if (context_lost_)
106    return GL_FRAMEBUFFER_UNDEFINED_OES;
107  return GL_FRAMEBUFFER_COMPLETE;
108}
109
110GLint TestWebGraphicsContext3D::getUniformLocation(
111    GLuint program,
112    const GLchar* name) {
113  return 0;
114}
115
116GLsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset(
117    GLuint index,
118    GLenum pname) {
119  return 0;
120}
121
122GLboolean TestWebGraphicsContext3D::isBuffer(
123    GLuint buffer) {
124  return false;
125}
126
127GLboolean TestWebGraphicsContext3D::isEnabled(
128    GLenum cap) {
129  return false;
130}
131
132GLboolean TestWebGraphicsContext3D::isFramebuffer(
133    GLuint framebuffer) {
134  return false;
135}
136
137GLboolean TestWebGraphicsContext3D::isProgram(
138    GLuint program) {
139  return false;
140}
141
142GLboolean TestWebGraphicsContext3D::isRenderbuffer(
143    GLuint renderbuffer) {
144  return false;
145}
146
147GLboolean TestWebGraphicsContext3D::isShader(
148    GLuint shader) {
149  return false;
150}
151
152GLboolean TestWebGraphicsContext3D::isTexture(
153    GLuint texture) {
154  return false;
155}
156
157void TestWebGraphicsContext3D::genBuffers(GLsizei count, GLuint* ids) {
158  for (int i = 0; i < count; ++i)
159    ids[i] = NextBufferId();
160}
161
162void TestWebGraphicsContext3D::genFramebuffers(
163    GLsizei count, GLuint* ids) {
164  for (int i = 0; i < count; ++i)
165    ids[i] = kFramebufferId | context_id_ << 16;
166}
167
168void TestWebGraphicsContext3D::genRenderbuffers(
169    GLsizei count, GLuint* ids) {
170  for (int i = 0; i < count; ++i)
171    ids[i] = kRenderbufferId | context_id_ << 16;
172}
173
174void TestWebGraphicsContext3D::genTextures(GLsizei count, GLuint* ids) {
175  for (int i = 0; i < count; ++i) {
176    ids[i] = NextTextureId();
177    DCHECK_NE(ids[i], kExternalTextureId);
178  }
179  base::AutoLock lock(namespace_->lock);
180  for (int i = 0; i < count; ++i)
181    namespace_->textures.Append(ids[i], new TestTexture());
182}
183
184void TestWebGraphicsContext3D::deleteBuffers(GLsizei count, GLuint* ids) {
185  for (int i = 0; i < count; ++i)
186    RetireBufferId(ids[i]);
187}
188
189void TestWebGraphicsContext3D::deleteFramebuffers(
190    GLsizei count, GLuint* ids) {
191  for (int i = 0; i < count; ++i)
192    DCHECK_EQ(kFramebufferId | context_id_ << 16, ids[i]);
193}
194
195void TestWebGraphicsContext3D::deleteRenderbuffers(
196    GLsizei count, GLuint* ids) {
197  for (int i = 0; i < count; ++i)
198    DCHECK_EQ(kRenderbufferId | context_id_ << 16, ids[i]);
199}
200
201void TestWebGraphicsContext3D::deleteTextures(GLsizei count, GLuint* ids) {
202  for (int i = 0; i < count; ++i)
203    RetireTextureId(ids[i]);
204  base::AutoLock lock(namespace_->lock);
205  for (int i = 0; i < count; ++i) {
206    namespace_->textures.Remove(ids[i]);
207    texture_targets_.UnbindTexture(ids[i]);
208  }
209}
210
211GLuint TestWebGraphicsContext3D::createBuffer() {
212  GLuint id;
213  genBuffers(1, &id);
214  return id;
215}
216
217GLuint TestWebGraphicsContext3D::createFramebuffer() {
218  GLuint id;
219  genFramebuffers(1, &id);
220  return id;
221}
222
223GLuint TestWebGraphicsContext3D::createRenderbuffer() {
224  GLuint id;
225  genRenderbuffers(1, &id);
226  return id;
227}
228
229GLuint TestWebGraphicsContext3D::createTexture() {
230  GLuint id;
231  genTextures(1, &id);
232  return id;
233}
234
235void TestWebGraphicsContext3D::deleteBuffer(GLuint id) {
236  deleteBuffers(1, &id);
237}
238
239void TestWebGraphicsContext3D::deleteFramebuffer(GLuint id) {
240  deleteFramebuffers(1, &id);
241}
242
243void TestWebGraphicsContext3D::deleteRenderbuffer(GLuint id) {
244  deleteRenderbuffers(1, &id);
245}
246
247void TestWebGraphicsContext3D::deleteTexture(GLuint id) {
248  deleteTextures(1, &id);
249}
250
251unsigned TestWebGraphicsContext3D::createProgram() {
252  unsigned program = next_program_id_++ | context_id_ << 16;
253  program_set_.insert(program);
254  return program;
255}
256
257GLuint TestWebGraphicsContext3D::createShader(GLenum) {
258  unsigned shader = next_shader_id_++ | context_id_ << 16;
259  shader_set_.insert(shader);
260  return shader;
261}
262
263GLuint TestWebGraphicsContext3D::createExternalTexture() {
264  base::AutoLock lock(namespace_->lock);
265  namespace_->textures.Append(kExternalTextureId, new TestTexture());
266  return kExternalTextureId;
267}
268
269void TestWebGraphicsContext3D::deleteProgram(GLuint id) {
270  if (!program_set_.count(id))
271    ADD_FAILURE() << "deleteProgram called on unknown program " << id;
272  program_set_.erase(id);
273}
274
275void TestWebGraphicsContext3D::deleteShader(GLuint id) {
276  if (!shader_set_.count(id))
277    ADD_FAILURE() << "deleteShader called on unknown shader " << id;
278  shader_set_.erase(id);
279}
280
281void TestWebGraphicsContext3D::attachShader(GLuint program, GLuint shader) {
282  if (!program_set_.count(program))
283    ADD_FAILURE() << "attachShader called with unknown program " << program;
284  if (!shader_set_.count(shader))
285    ADD_FAILURE() << "attachShader called with unknown shader " << shader;
286}
287
288void TestWebGraphicsContext3D::useProgram(GLuint program) {
289  if (!program)
290    return;
291  if (!program_set_.count(program))
292    ADD_FAILURE() << "useProgram called on unknown program " << program;
293}
294
295void TestWebGraphicsContext3D::bindFramebuffer(
296    GLenum target, GLuint framebuffer) {
297  if (!framebuffer)
298    return;
299  DCHECK_EQ(kFramebufferId | context_id_ << 16, framebuffer);
300}
301
302void TestWebGraphicsContext3D::bindRenderbuffer(
303      GLenum target, GLuint renderbuffer) {
304  if (!renderbuffer)
305    return;
306  DCHECK_EQ(kRenderbufferId | context_id_ << 16, renderbuffer);
307}
308
309void TestWebGraphicsContext3D::bindTexture(
310    GLenum target, GLuint texture_id) {
311  if (times_bind_texture_succeeds_ >= 0) {
312    if (!times_bind_texture_succeeds_) {
313      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
314                          GL_INNOCENT_CONTEXT_RESET_ARB);
315    }
316    --times_bind_texture_succeeds_;
317  }
318
319  if (!texture_id)
320    return;
321  base::AutoLock lock(namespace_->lock);
322  DCHECK(namespace_->textures.ContainsId(texture_id));
323  texture_targets_.BindTexture(target, texture_id);
324  used_textures_.insert(texture_id);
325}
326
327GLuint TestWebGraphicsContext3D::BoundTextureId(
328    GLenum target) {
329  return texture_targets_.BoundTexture(target);
330}
331
332scoped_refptr<TestTexture> TestWebGraphicsContext3D::BoundTexture(
333    GLenum target) {
334  // The caller is expected to lock the namespace for texture access.
335  namespace_->lock.AssertAcquired();
336  return namespace_->textures.TextureForId(BoundTextureId(target));
337}
338
339void TestWebGraphicsContext3D::CheckTextureIsBound(GLenum target) {
340  DCHECK(BoundTextureId(target));
341}
342
343GLuint TestWebGraphicsContext3D::createQueryEXT() { return 1u; }
344
345void TestWebGraphicsContext3D::endQueryEXT(GLenum target) {
346  if (times_end_query_succeeds_ >= 0) {
347    if (!times_end_query_succeeds_) {
348      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
349                          GL_INNOCENT_CONTEXT_RESET_ARB);
350    }
351    --times_end_query_succeeds_;
352  }
353}
354
355void TestWebGraphicsContext3D::getQueryObjectuivEXT(
356    GLuint query,
357    GLenum pname,
358    GLuint* params) {
359  // If the context is lost, behave as if result is available.
360  if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
361    *params = 1;
362}
363
364void TestWebGraphicsContext3D::getIntegerv(
365    GLenum pname,
366    GLint* value) {
367  if (pname == GL_MAX_TEXTURE_SIZE)
368    *value = max_texture_size_;
369  else if (pname == GL_ACTIVE_TEXTURE)
370    *value = GL_TEXTURE0;
371}
372
373void TestWebGraphicsContext3D::getProgramiv(GLuint program,
374                                            GLenum pname,
375                                            GLint* value) {
376  if (pname == GL_LINK_STATUS)
377    *value = 1;
378}
379
380void TestWebGraphicsContext3D::getShaderiv(GLuint shader,
381                                           GLenum pname,
382                                           GLint* value) {
383  if (pname == GL_COMPILE_STATUS)
384    *value = 1;
385}
386
387void TestWebGraphicsContext3D::getShaderPrecisionFormat(GLenum shadertype,
388                                                        GLenum precisiontype,
389                                                        GLint* range,
390                                                        GLint* precision) {
391  // Return the minimum precision requirements of the GLES2
392  // specification.
393  switch (precisiontype) {
394    case GL_LOW_INT:
395      range[0] = 8;
396      range[1] = 8;
397      *precision = 0;
398      break;
399    case GL_MEDIUM_INT:
400      range[0] = 10;
401      range[1] = 10;
402      *precision = 0;
403      break;
404    case GL_HIGH_INT:
405      range[0] = 16;
406      range[1] = 16;
407      *precision = 0;
408      break;
409    case GL_LOW_FLOAT:
410      range[0] = 8;
411      range[1] = 8;
412      *precision = 8;
413      break;
414    case GL_MEDIUM_FLOAT:
415      range[0] = 14;
416      range[1] = 14;
417      *precision = 10;
418      break;
419    case GL_HIGH_FLOAT:
420      range[0] = 62;
421      range[1] = 62;
422      *precision = 16;
423      break;
424    default:
425      NOTREACHED();
426      break;
427  }
428}
429
430void TestWebGraphicsContext3D::genMailboxCHROMIUM(GLbyte* mailbox) {
431  static char mailbox_name1 = '1';
432  static char mailbox_name2 = '1';
433  mailbox[0] = mailbox_name1;
434  mailbox[1] = mailbox_name2;
435  mailbox[2] = '\0';
436  if (++mailbox_name1 == 0) {
437    mailbox_name1 = '1';
438    ++mailbox_name2;
439  }
440}
441
442GLuint TestWebGraphicsContext3D::createAndConsumeTextureCHROMIUM(
443    GLenum target,
444    const GLbyte* mailbox) {
445  return createTexture();
446}
447
448void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current,
449                                                   GLenum other) {
450  if (context_lost_)
451    return;
452  context_lost_ = true;
453  if (!context_lost_callback_.is_null())
454    context_lost_callback_.Run();
455
456  for (size_t i = 0; i < shared_contexts_.size(); ++i)
457    shared_contexts_[i]->loseContextCHROMIUM(current, other);
458  shared_contexts_.clear();
459}
460
461void TestWebGraphicsContext3D::finish() {
462  test_support_->CallAllSyncPointCallbacks();
463}
464
465void TestWebGraphicsContext3D::flush() {
466  test_support_->CallAllSyncPointCallbacks();
467}
468
469GLint TestWebGraphicsContext3D::getAttribLocation(GLuint program,
470                                                  const GLchar* name) {
471  return 0;
472}
473
474GLenum TestWebGraphicsContext3D::getError() { return GL_NO_ERROR; }
475
476void TestWebGraphicsContext3D::bindBuffer(GLenum target,
477                                          GLuint buffer) {
478  bound_buffer_ = buffer;
479  if (!bound_buffer_)
480    return;
481  unsigned context_id = buffer >> 16;
482  unsigned buffer_id = buffer & 0xffff;
483  base::AutoLock lock(namespace_->lock);
484  DCHECK(buffer_id);
485  DCHECK_LT(buffer_id, namespace_->next_buffer_id);
486  DCHECK_EQ(context_id, context_id_);
487
488  base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
489  if (buffers.count(bound_buffer_) == 0)
490    buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass());
491
492  buffers.get(bound_buffer_)->target = target;
493}
494
495void TestWebGraphicsContext3D::bufferData(GLenum target,
496                                          GLsizeiptr size,
497                                          const void* data,
498                                          GLenum usage) {
499  base::AutoLock lock(namespace_->lock);
500  base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
501  DCHECK_GT(buffers.count(bound_buffer_), 0u);
502  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
503  Buffer* buffer = buffers.get(bound_buffer_);
504  if (context_lost_) {
505    buffer->pixels.reset();
506    return;
507  }
508
509  size_t old_size = buffer->size;
510
511  buffer->pixels.reset(new uint8[size]);
512  buffer->size = size;
513  if (data != NULL)
514    memcpy(buffer->pixels.get(), data, size);
515  if (buffer->target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM)
516    current_used_transfer_buffer_usage_bytes_ += buffer->size - old_size;
517  max_used_transfer_buffer_usage_bytes_ =
518      std::max(max_used_transfer_buffer_usage_bytes_,
519               current_used_transfer_buffer_usage_bytes_);
520}
521
522void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target,
523                                                  GLenum access) {
524  base::AutoLock lock(namespace_->lock);
525  base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
526  DCHECK_GT(buffers.count(bound_buffer_), 0u);
527  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
528  if (times_map_buffer_chromium_succeeds_ >= 0) {
529    if (!times_map_buffer_chromium_succeeds_) {
530      return NULL;
531    }
532    --times_map_buffer_chromium_succeeds_;
533  }
534
535  return buffers.get(bound_buffer_)->pixels.get();
536}
537
538GLboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM(
539    GLenum target) {
540  base::AutoLock lock(namespace_->lock);
541  base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
542  DCHECK_GT(buffers.count(bound_buffer_), 0u);
543  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
544  buffers.get(bound_buffer_)->pixels.reset();
545  return true;
546}
547
548GLuint TestWebGraphicsContext3D::createImageCHROMIUM(GLsizei width,
549                                                     GLsizei height,
550                                                     GLenum internalformat,
551                                                     GLenum usage) {
552  DCHECK_EQ(GL_RGBA8_OES, static_cast<int>(internalformat));
553  GLuint image_id = NextImageId();
554  base::AutoLock lock(namespace_->lock);
555  base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
556  images.set(image_id, make_scoped_ptr(new Image).Pass());
557  images.get(image_id)->pixels.reset(new uint8[width * height * 4]);
558  return image_id;
559}
560
561void TestWebGraphicsContext3D::destroyImageCHROMIUM(
562    GLuint id) {
563  RetireImageId(id);
564}
565
566void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
567    GLuint image_id,
568    GLenum pname,
569    GLint* params) {
570  base::AutoLock lock(namespace_->lock);
571  DCHECK_GT(namespace_->images.count(image_id), 0u);
572  DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM, static_cast<int>(pname));
573  *params = 0;
574}
575
576void* TestWebGraphicsContext3D::mapImageCHROMIUM(GLuint image_id) {
577  base::AutoLock lock(namespace_->lock);
578  base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
579  DCHECK_GT(images.count(image_id), 0u);
580  if (times_map_image_chromium_succeeds_ >= 0) {
581    if (!times_map_image_chromium_succeeds_) {
582      return NULL;
583    }
584    --times_map_image_chromium_succeeds_;
585  }
586  return images.get(image_id)->pixels.get();
587}
588
589void TestWebGraphicsContext3D::unmapImageCHROMIUM(
590    GLuint image_id) {
591  base::AutoLock lock(namespace_->lock);
592  DCHECK_GT(namespace_->images.count(image_id), 0u);
593}
594
595unsigned TestWebGraphicsContext3D::insertSyncPoint() {
596  return next_insert_sync_point_++;
597}
598
599void TestWebGraphicsContext3D::waitSyncPoint(unsigned sync_point) {
600  if (sync_point)
601    last_waited_sync_point_ = sync_point;
602}
603
604size_t TestWebGraphicsContext3D::NumTextures() const {
605  base::AutoLock lock(namespace_->lock);
606  return namespace_->textures.Size();
607}
608
609GLuint TestWebGraphicsContext3D::TextureAt(int i) const {
610  base::AutoLock lock(namespace_->lock);
611  return namespace_->textures.IdAt(i);
612}
613
614GLuint TestWebGraphicsContext3D::NextTextureId() {
615  base::AutoLock lock(namespace_->lock);
616  GLuint texture_id = namespace_->next_texture_id++;
617  DCHECK(texture_id < (1 << 16));
618  texture_id |= context_id_ << 16;
619  return texture_id;
620}
621
622void TestWebGraphicsContext3D::RetireTextureId(GLuint id) {
623  base::AutoLock lock(namespace_->lock);
624  unsigned context_id = id >> 16;
625  unsigned texture_id = id & 0xffff;
626  DCHECK(texture_id);
627  DCHECK_LT(texture_id, namespace_->next_texture_id);
628  DCHECK_EQ(context_id, context_id_);
629}
630
631GLuint TestWebGraphicsContext3D::NextBufferId() {
632  base::AutoLock lock(namespace_->lock);
633  GLuint buffer_id = namespace_->next_buffer_id++;
634  DCHECK(buffer_id < (1 << 16));
635  buffer_id |= context_id_ << 16;
636  return buffer_id;
637}
638
639void TestWebGraphicsContext3D::RetireBufferId(GLuint id) {
640  base::AutoLock lock(namespace_->lock);
641  unsigned context_id = id >> 16;
642  unsigned buffer_id = id & 0xffff;
643  DCHECK(buffer_id);
644  DCHECK_LT(buffer_id, namespace_->next_buffer_id);
645  DCHECK_EQ(context_id, context_id_);
646}
647
648GLuint TestWebGraphicsContext3D::NextImageId() {
649  base::AutoLock lock(namespace_->lock);
650  GLuint image_id = namespace_->next_image_id++;
651  DCHECK(image_id < (1 << 16));
652  image_id |= context_id_ << 16;
653  return image_id;
654}
655
656void TestWebGraphicsContext3D::RetireImageId(GLuint id) {
657  base::AutoLock lock(namespace_->lock);
658  unsigned context_id = id >> 16;
659  unsigned image_id = id & 0xffff;
660  DCHECK(image_id);
661  DCHECK_LT(image_id, namespace_->next_image_id);
662  DCHECK_EQ(context_id, context_id_);
663}
664
665void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes(
666    size_t max_transfer_buffer_usage_bytes) {
667  test_capabilities_.max_transfer_buffer_usage_bytes =
668      max_transfer_buffer_usage_bytes;
669}
670
671TestWebGraphicsContext3D::TextureTargets::TextureTargets() {
672  // Initialize default bindings.
673  bound_textures_[GL_TEXTURE_2D] = 0;
674  bound_textures_[GL_TEXTURE_EXTERNAL_OES] = 0;
675  bound_textures_[GL_TEXTURE_RECTANGLE_ARB] = 0;
676}
677
678TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {}
679
680void TestWebGraphicsContext3D::TextureTargets::BindTexture(
681    GLenum target,
682    GLuint id) {
683  // Make sure this is a supported target by seeing if it was bound to before.
684  DCHECK(bound_textures_.find(target) != bound_textures_.end());
685  bound_textures_[target] = id;
686}
687
688void TestWebGraphicsContext3D::texParameteri(GLenum target,
689                                             GLenum pname,
690                                             GLint param) {
691  CheckTextureIsBound(target);
692  base::AutoLock lock_for_texture_access(namespace_->lock);
693  scoped_refptr<TestTexture> texture = BoundTexture(target);
694  DCHECK(texture->IsValidParameter(pname));
695  texture->params[pname] = param;
696}
697
698void TestWebGraphicsContext3D::getTexParameteriv(GLenum target,
699                                                 GLenum pname,
700                                                 GLint* value) {
701  CheckTextureIsBound(target);
702  base::AutoLock lock_for_texture_access(namespace_->lock);
703  scoped_refptr<TestTexture> texture = BoundTexture(target);
704  DCHECK(texture->IsValidParameter(pname));
705  TestTexture::TextureParametersMap::iterator it = texture->params.find(pname);
706  if (it != texture->params.end())
707    *value = it->second;
708}
709
710void TestWebGraphicsContext3D::TextureTargets::UnbindTexture(
711    GLuint id) {
712  // Bind zero to any targets that the id is bound to.
713  for (TargetTextureMap::iterator it = bound_textures_.begin();
714       it != bound_textures_.end();
715       it++) {
716    if (it->second == id)
717      it->second = 0;
718  }
719}
720
721GLuint TestWebGraphicsContext3D::TextureTargets::BoundTexture(
722    GLenum target) {
723  DCHECK(bound_textures_.find(target) != bound_textures_.end());
724  return bound_textures_[target];
725}
726
727TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {}
728
729TestWebGraphicsContext3D::Buffer::~Buffer() {}
730
731TestWebGraphicsContext3D::Image::Image() {}
732
733TestWebGraphicsContext3D::Image::~Image() {}
734
735}  // namespace cc
736