• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // A class to emulate GLES2 over command buffers.
6 
7 #include "gpu/command_buffer/client/gles2_implementation.h"
8 
9 #include <algorithm>
10 #include <map>
11 #include <queue>
12 #include <set>
13 #include <limits>
14 #include <stdio.h>
15 #include <string.h>
16 #include <GLES2/gl2ext.h>
17 #include <GLES2/gl2extchromium.h>
18 #include "gpu/command_buffer/client/buffer_tracker.h"
19 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
20 #include "gpu/command_buffer/client/program_info_manager.h"
21 #include "gpu/command_buffer/client/query_tracker.h"
22 #include "gpu/command_buffer/client/transfer_buffer.h"
23 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
24 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
25 #include "gpu/command_buffer/common/gpu_control.h"
26 #include "gpu/command_buffer/common/trace_event.h"
27 #include "ui/gfx/gpu_memory_buffer.h"
28 
29 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
30 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
31 #endif
32 
33 #if defined(GPU_CLIENT_DEBUG)
34 #include "ui/gl/gl_switches.h"
35 #include "base/command_line.h"
36 #endif
37 
38 namespace gpu {
39 namespace gles2 {
40 
41 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
ToGLuint(const void * ptr)42 static GLuint ToGLuint(const void* ptr) {
43   return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
44 }
45 
46 #if !defined(_MSC_VER)
47 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
48 const unsigned int GLES2Implementation::kStartingOffset;
49 #endif
50 
GLStaticState()51 GLES2Implementation::GLStaticState::GLStaticState() {
52 }
53 
~GLStaticState()54 GLES2Implementation::GLStaticState::~GLStaticState() {
55 }
56 
IntState()57 GLES2Implementation::GLStaticState::IntState::IntState()
58     : max_combined_texture_image_units(0),
59       max_cube_map_texture_size(0),
60       max_fragment_uniform_vectors(0),
61       max_renderbuffer_size(0),
62       max_texture_image_units(0),
63       max_texture_size(0),
64       max_varying_vectors(0),
65       max_vertex_attribs(0),
66       max_vertex_texture_image_units(0),
67       max_vertex_uniform_vectors(0),
68       num_compressed_texture_formats(0),
69       num_shader_binary_formats(0) {
70 }
71 
SingleThreadChecker(GLES2Implementation * gles2_implementation)72 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
73     GLES2Implementation* gles2_implementation)
74     : gles2_implementation_(gles2_implementation) {
75   CHECK_EQ(0, gles2_implementation_->use_count_);
76   ++gles2_implementation_->use_count_;
77 }
78 
~SingleThreadChecker()79 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
80   --gles2_implementation_->use_count_;
81   CHECK_EQ(0, gles2_implementation_->use_count_);
82 }
83 
GLES2Implementation(GLES2CmdHelper * helper,ShareGroup * share_group,TransferBufferInterface * transfer_buffer,bool bind_generates_resource,bool free_everything_when_invisible,GpuControl * gpu_control)84 GLES2Implementation::GLES2Implementation(
85       GLES2CmdHelper* helper,
86       ShareGroup* share_group,
87       TransferBufferInterface* transfer_buffer,
88       bool bind_generates_resource,
89       bool free_everything_when_invisible,
90       GpuControl* gpu_control)
91     : helper_(helper),
92       transfer_buffer_(transfer_buffer),
93       angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
94       chromium_framebuffer_multisample_(kUnknownExtensionStatus),
95       pack_alignment_(4),
96       unpack_alignment_(4),
97       unpack_flip_y_(false),
98       unpack_row_length_(0),
99       unpack_skip_rows_(0),
100       unpack_skip_pixels_(0),
101       pack_reverse_row_order_(false),
102       active_texture_unit_(0),
103       bound_framebuffer_(0),
104       bound_read_framebuffer_(0),
105       bound_renderbuffer_(0),
106       current_program_(0),
107       bound_array_buffer_id_(0),
108       bound_pixel_pack_transfer_buffer_id_(0),
109       bound_pixel_unpack_transfer_buffer_id_(0),
110       error_bits_(0),
111       debug_(false),
112       use_count_(0),
113       current_query_(NULL),
114       error_message_callback_(NULL),
115       gpu_control_(gpu_control),
116       surface_visible_(true),
117       free_everything_when_invisible_(free_everything_when_invisible),
118       capabilities_(gpu_control->GetCapabilities()),
119       weak_ptr_factory_(this) {
120   DCHECK(helper);
121   DCHECK(transfer_buffer);
122   DCHECK(gpu_control);
123 
124   char temp[128];
125   sprintf(temp, "%p", static_cast<void*>(this));
126   this_in_hex_ = std::string(temp);
127 
128   GPU_CLIENT_LOG_CODE_BLOCK({
129     debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
130         switches::kEnableGPUClientLogging);
131   });
132 
133   share_group_ =
134       (share_group ? share_group : new ShareGroup(bind_generates_resource));
135 
136   memset(&reserved_ids_, 0, sizeof(reserved_ids_));
137 }
138 
Initialize(unsigned int starting_transfer_buffer_size,unsigned int min_transfer_buffer_size,unsigned int max_transfer_buffer_size,unsigned int mapped_memory_limit)139 bool GLES2Implementation::Initialize(
140     unsigned int starting_transfer_buffer_size,
141     unsigned int min_transfer_buffer_size,
142     unsigned int max_transfer_buffer_size,
143     unsigned int mapped_memory_limit) {
144   DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
145   DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
146   DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
147 
148   if (!transfer_buffer_->Initialize(
149       starting_transfer_buffer_size,
150       kStartingOffset,
151       min_transfer_buffer_size,
152       max_transfer_buffer_size,
153       kAlignment,
154       kSizeToFlush)) {
155     return false;
156   }
157 
158   mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
159 
160   unsigned chunk_size = 2 * 1024 * 1024;
161   if (mapped_memory_limit != kNoLimit) {
162     // Use smaller chunks if the client is very memory conscientious.
163     chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
164   }
165   mapped_memory_->set_chunk_size_multiple(chunk_size);
166 
167   if (!QueryAndCacheStaticState())
168     return false;
169 
170   util_.set_num_compressed_texture_formats(
171       static_state_.int_state.num_compressed_texture_formats);
172   util_.set_num_shader_binary_formats(
173       static_state_.int_state.num_shader_binary_formats);
174 
175   texture_units_.reset(
176       new TextureUnit[
177           static_state_.int_state.max_combined_texture_image_units]);
178 
179   query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
180   buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
181   gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
182 
183 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
184   GetIdHandler(id_namespaces::kBuffers)->MakeIds(
185       this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
186 #endif
187 
188   vertex_array_object_manager_.reset(new VertexArrayObjectManager(
189       static_state_.int_state.max_vertex_attribs,
190       reserved_ids_[0],
191       reserved_ids_[1]));
192 
193   return true;
194 }
195 
QueryAndCacheStaticState()196 bool GLES2Implementation::QueryAndCacheStaticState() {
197   // Setup query for multiple GetIntegerv's
198   static const GLenum pnames[] = {
199     GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
200     GL_MAX_CUBE_MAP_TEXTURE_SIZE,
201     GL_MAX_FRAGMENT_UNIFORM_VECTORS,
202     GL_MAX_RENDERBUFFER_SIZE,
203     GL_MAX_TEXTURE_IMAGE_UNITS,
204     GL_MAX_TEXTURE_SIZE,
205     GL_MAX_VARYING_VECTORS,
206     GL_MAX_VERTEX_ATTRIBS,
207     GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
208     GL_MAX_VERTEX_UNIFORM_VECTORS,
209     GL_NUM_COMPRESSED_TEXTURE_FORMATS,
210     GL_NUM_SHADER_BINARY_FORMATS,
211   };
212 
213   GetMultipleIntegervState integerv_state(
214       pnames, arraysize(pnames),
215       &static_state_.int_state.max_combined_texture_image_units,
216       sizeof(static_state_.int_state));
217   if (!GetMultipleIntegervSetup(&integerv_state)) {
218     return false;
219   }
220 
221   // Setup query for multiple GetShaderPrecisionFormat's
222   static const GLenum precision_params[][2] = {
223     { GL_VERTEX_SHADER, GL_LOW_INT },
224     { GL_VERTEX_SHADER, GL_MEDIUM_INT },
225     { GL_VERTEX_SHADER, GL_HIGH_INT },
226     { GL_VERTEX_SHADER, GL_LOW_FLOAT },
227     { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
228     { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
229     { GL_FRAGMENT_SHADER, GL_LOW_INT },
230     { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
231     { GL_FRAGMENT_SHADER, GL_HIGH_INT },
232     { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
233     { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
234     { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
235   };
236 
237   GetAllShaderPrecisionFormatsState  precision_state(
238       precision_params, arraysize(precision_params));
239   GetAllShaderPrecisionFormatsSetup(&precision_state);
240 
241   // Allocate and partition transfer buffer for all requests
242   void* buffer = transfer_buffer_->Alloc(
243       integerv_state.transfer_buffer_size_needed +
244       precision_state.transfer_buffer_size_needed);
245   if (!buffer) {
246     SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
247                "Transfer buffer allocation failed.");
248     return false;
249   }
250   integerv_state.buffer = buffer;
251   precision_state.results_buffer =
252       static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
253 
254   // Make all the requests and wait once for all the results.
255   GetMultipleIntegervRequest(&integerv_state);
256   GetAllShaderPrecisionFormatsRequest(&precision_state);
257   WaitForCmd();
258   GetMultipleIntegervOnCompleted(&integerv_state);
259   GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
260 
261   // TODO(gman): We should be able to free without a token.
262   transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
263   CheckGLError();
264 
265   return true;
266 }
267 
~GLES2Implementation()268 GLES2Implementation::~GLES2Implementation() {
269   // Make sure the queries are finished otherwise we'll delete the
270   // shared memory (mapped_memory_) which will free the memory used
271   // by the queries. The GPU process when validating that memory is still
272   // shared will fail and abort (ie, it will stop running).
273   WaitForCmd();
274   query_tracker_.reset();
275 
276 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
277   DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
278 #endif
279   buffer_tracker_.reset();
280 
281   // Make sure the commands make it the service.
282   WaitForCmd();
283 }
284 
helper() const285 GLES2CmdHelper* GLES2Implementation::helper() const {
286   return helper_;
287 }
288 
GetIdHandler(int namespace_id) const289 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
290   return share_group_->GetIdHandler(namespace_id);
291 }
292 
GetResultBuffer()293 void* GLES2Implementation::GetResultBuffer() {
294   return transfer_buffer_->GetResultBuffer();
295 }
296 
GetResultShmId()297 int32 GLES2Implementation::GetResultShmId() {
298   return transfer_buffer_->GetShmId();
299 }
300 
GetResultShmOffset()301 uint32 GLES2Implementation::GetResultShmOffset() {
302   return transfer_buffer_->GetResultOffset();
303 }
304 
FreeUnusedSharedMemory()305 void GLES2Implementation::FreeUnusedSharedMemory() {
306   mapped_memory_->FreeUnused();
307 }
308 
FreeEverything()309 void GLES2Implementation::FreeEverything() {
310   WaitForCmd();
311   query_tracker_->Shrink();
312   FreeUnusedSharedMemory();
313   transfer_buffer_->Free();
314   helper_->FreeRingBuffer();
315 }
316 
RunIfContextNotLost(const base::Closure & callback)317 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
318   if (!helper_->IsContextLost())
319     callback.Run();
320 }
321 
SignalSyncPoint(uint32 sync_point,const base::Closure & callback)322 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
323                                           const base::Closure& callback) {
324   gpu_control_->SignalSyncPoint(
325       sync_point,
326       base::Bind(&GLES2Implementation::RunIfContextNotLost,
327                  weak_ptr_factory_.GetWeakPtr(),
328                  callback));
329 }
330 
SignalQuery(uint32 query,const base::Closure & callback)331 void GLES2Implementation::SignalQuery(uint32 query,
332                                       const base::Closure& callback) {
333   // Flush previously entered commands to ensure ordering with any
334   // glBeginQueryEXT() calls that may have been put into the context.
335   ShallowFlushCHROMIUM();
336   gpu_control_->SignalQuery(
337       query,
338       base::Bind(&GLES2Implementation::RunIfContextNotLost,
339                  weak_ptr_factory_.GetWeakPtr(),
340                  callback));
341 }
342 
SetSurfaceVisible(bool visible)343 void GLES2Implementation::SetSurfaceVisible(bool visible) {
344   // TODO(piman): This probably should be ShallowFlushCHROMIUM().
345   Flush();
346   surface_visible_ = visible;
347   gpu_control_->SetSurfaceVisible(visible);
348   if (!visible)
349     FreeEverything();
350 }
351 
SendManagedMemoryStats(const ManagedMemoryStats & stats)352 void GLES2Implementation::SendManagedMemoryStats(
353     const ManagedMemoryStats& stats) {
354   gpu_control_->SendManagedMemoryStats(stats);
355 }
356 
WaitForCmd()357 void GLES2Implementation::WaitForCmd() {
358   TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
359   helper_->CommandBufferHelper::Finish();
360 }
361 
IsExtensionAvailable(const char * ext)362 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
363   const char* extensions =
364       reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
365   if (!extensions)
366     return false;
367 
368   int length = strlen(ext);
369   while (true) {
370     int n = strcspn(extensions, " ");
371     if (n == length && 0 == strncmp(ext, extensions, length)) {
372       return true;
373     }
374     if ('\0' == extensions[n]) {
375       return false;
376     }
377     extensions += n + 1;
378   }
379 }
380 
IsExtensionAvailableHelper(const char * extension,ExtensionStatus * status)381 bool GLES2Implementation::IsExtensionAvailableHelper(
382     const char* extension, ExtensionStatus* status) {
383   switch (*status) {
384     case kAvailableExtensionStatus:
385       return true;
386     case kUnavailableExtensionStatus:
387       return false;
388     default: {
389       bool available = IsExtensionAvailable(extension);
390       *status = available ? kAvailableExtensionStatus :
391                             kUnavailableExtensionStatus;
392       return available;
393     }
394   }
395 }
396 
IsAnglePackReverseRowOrderAvailable()397 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
398   return IsExtensionAvailableHelper(
399       "GL_ANGLE_pack_reverse_row_order",
400       &angle_pack_reverse_row_order_status_);
401 }
402 
IsChromiumFramebufferMultisampleAvailable()403 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
404   return IsExtensionAvailableHelper(
405       "GL_CHROMIUM_framebuffer_multisample",
406       &chromium_framebuffer_multisample_);
407 }
408 
GetLogPrefix() const409 const std::string& GLES2Implementation::GetLogPrefix() const {
410   const std::string& prefix(debug_marker_manager_.GetMarker());
411   return prefix.empty() ? this_in_hex_ : prefix;
412 }
413 
GetError()414 GLenum GLES2Implementation::GetError() {
415   GPU_CLIENT_SINGLE_THREAD_CHECK();
416   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
417   GLenum err = GetGLError();
418   GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
419   return err;
420 }
421 
GetClientSideGLError()422 GLenum GLES2Implementation::GetClientSideGLError() {
423   if (error_bits_ == 0) {
424     return GL_NO_ERROR;
425   }
426 
427   GLenum error = GL_NO_ERROR;
428   for (uint32 mask = 1; mask != 0; mask = mask << 1) {
429     if ((error_bits_ & mask) != 0) {
430       error = GLES2Util::GLErrorBitToGLError(mask);
431       break;
432     }
433   }
434   error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
435   return error;
436 }
437 
GetGLError()438 GLenum GLES2Implementation::GetGLError() {
439   TRACE_EVENT0("gpu", "GLES2::GetGLError");
440   // Check the GL error first, then our wrapped error.
441   typedef cmds::GetError::Result Result;
442   Result* result = GetResultAs<Result*>();
443   // If we couldn't allocate a result the context is lost.
444   if (!result) {
445     return GL_NO_ERROR;
446   }
447   *result = GL_NO_ERROR;
448   helper_->GetError(GetResultShmId(), GetResultShmOffset());
449   WaitForCmd();
450   GLenum error = *result;
451   if (error == GL_NO_ERROR) {
452     error = GetClientSideGLError();
453   } else {
454     // There was an error, clear the corresponding wrapped error.
455     error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
456   }
457   return error;
458 }
459 
460 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
FailGLError(GLenum error)461 void GLES2Implementation::FailGLError(GLenum error) {
462   if (error != GL_NO_ERROR) {
463     NOTREACHED() << "Error";
464   }
465 }
466 // NOTE: Calling GetGLError overwrites data in the result buffer.
CheckGLError()467 void GLES2Implementation::CheckGLError() {
468   FailGLError(GetGLError());
469 }
470 #endif  // defined(GPU_CLIENT_FAIL_GL_ERRORS)
471 
SetGLError(GLenum error,const char * function_name,const char * msg)472 void GLES2Implementation::SetGLError(
473     GLenum error, const char* function_name, const char* msg) {
474   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
475                  << GLES2Util::GetStringError(error) << ": "
476                  << function_name << ": " << msg);
477   FailGLError(error);
478   if (msg) {
479     last_error_ = msg;
480   }
481   if (error_message_callback_) {
482     std::string temp(GLES2Util::GetStringError(error)  + " : " +
483                      function_name + ": " + (msg ? msg : ""));
484     error_message_callback_->OnErrorMessage(temp.c_str(), 0);
485   }
486   error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
487 }
488 
SetGLErrorInvalidEnum(const char * function_name,GLenum value,const char * label)489 void GLES2Implementation::SetGLErrorInvalidEnum(
490     const char* function_name, GLenum value, const char* label) {
491   SetGLError(GL_INVALID_ENUM, function_name,
492              (std::string(label) + " was " +
493               GLES2Util::GetStringEnum(value)).c_str());
494 }
495 
GetBucketContents(uint32 bucket_id,std::vector<int8> * data)496 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
497                                             std::vector<int8>* data) {
498   TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
499   DCHECK(data);
500   const uint32 kStartSize = 32 * 1024;
501   ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
502   if (!buffer.valid()) {
503     return false;
504   }
505   typedef cmd::GetBucketStart::Result Result;
506   Result* result = GetResultAs<Result*>();
507   if (!result) {
508     return false;
509   }
510   *result = 0;
511   helper_->GetBucketStart(
512       bucket_id, GetResultShmId(), GetResultShmOffset(),
513       buffer.size(), buffer.shm_id(), buffer.offset());
514   WaitForCmd();
515   uint32 size = *result;
516   data->resize(size);
517   if (size > 0u) {
518     uint32 offset = 0;
519     while (size) {
520       if (!buffer.valid()) {
521         buffer.Reset(size);
522         if (!buffer.valid()) {
523           return false;
524         }
525         helper_->GetBucketData(
526             bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
527         WaitForCmd();
528       }
529       uint32 size_to_copy = std::min(size, buffer.size());
530       memcpy(&(*data)[offset], buffer.address(), size_to_copy);
531       offset += size_to_copy;
532       size -= size_to_copy;
533       buffer.Release();
534     };
535     // Free the bucket. This is not required but it does free up the memory.
536     // and we don't have to wait for the result so from the client's perspective
537     // it's cheap.
538     helper_->SetBucketSize(bucket_id, 0);
539   }
540   return true;
541 }
542 
SetBucketContents(uint32 bucket_id,const void * data,size_t size)543 void GLES2Implementation::SetBucketContents(
544     uint32 bucket_id, const void* data, size_t size) {
545   DCHECK(data);
546   helper_->SetBucketSize(bucket_id, size);
547   if (size > 0u) {
548     uint32 offset = 0;
549     while (size) {
550       ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
551       if (!buffer.valid()) {
552         return;
553       }
554       memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
555              buffer.size());
556       helper_->SetBucketData(
557           bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
558       offset += buffer.size();
559       size -= buffer.size();
560     }
561   }
562 }
563 
SetBucketAsCString(uint32 bucket_id,const char * str)564 void GLES2Implementation::SetBucketAsCString(
565     uint32 bucket_id, const char* str) {
566   // NOTE: strings are passed NULL terminated. That means the empty
567   // string will have a size of 1 and no-string will have a size of 0
568   if (str) {
569     SetBucketContents(bucket_id, str, strlen(str) + 1);
570   } else {
571     helper_->SetBucketSize(bucket_id, 0);
572   }
573 }
574 
GetBucketAsString(uint32 bucket_id,std::string * str)575 bool GLES2Implementation::GetBucketAsString(
576     uint32 bucket_id, std::string* str) {
577   DCHECK(str);
578   std::vector<int8> data;
579   // NOTE: strings are passed NULL terminated. That means the empty
580   // string will have a size of 1 and no-string will have a size of 0
581   if (!GetBucketContents(bucket_id, &data)) {
582     return false;
583   }
584   if (data.empty()) {
585     return false;
586   }
587   str->assign(&data[0], &data[0] + data.size() - 1);
588   return true;
589 }
590 
SetBucketAsString(uint32 bucket_id,const std::string & str)591 void GLES2Implementation::SetBucketAsString(
592     uint32 bucket_id, const std::string& str) {
593   // NOTE: strings are passed NULL terminated. That means the empty
594   // string will have a size of 1 and no-string will have a size of 0
595   SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
596 }
597 
Disable(GLenum cap)598 void GLES2Implementation::Disable(GLenum cap) {
599   GPU_CLIENT_SINGLE_THREAD_CHECK();
600   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
601                  << GLES2Util::GetStringCapability(cap) << ")");
602   bool changed = false;
603   if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
604     helper_->Disable(cap);
605   }
606   CheckGLError();
607 }
608 
Enable(GLenum cap)609 void GLES2Implementation::Enable(GLenum cap) {
610   GPU_CLIENT_SINGLE_THREAD_CHECK();
611   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
612                  << GLES2Util::GetStringCapability(cap) << ")");
613   bool changed = false;
614   if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
615     helper_->Enable(cap);
616   }
617   CheckGLError();
618 }
619 
IsEnabled(GLenum cap)620 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
621   GPU_CLIENT_SINGLE_THREAD_CHECK();
622   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
623                  << GLES2Util::GetStringCapability(cap) << ")");
624   bool state = false;
625   if (!state_.GetEnabled(cap, &state)) {
626     typedef cmds::IsEnabled::Result Result;
627     Result* result = GetResultAs<Result*>();
628     if (!result) {
629       return GL_FALSE;
630     }
631     *result = 0;
632     helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
633     WaitForCmd();
634     state = (*result) != 0;
635   }
636 
637   GPU_CLIENT_LOG("returned " << state);
638   CheckGLError();
639   return state;
640 }
641 
GetHelper(GLenum pname,GLint * params)642 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
643   switch (pname) {
644     case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
645       *params = static_state_.int_state.max_combined_texture_image_units;
646       return true;
647     case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
648       *params = static_state_.int_state.max_cube_map_texture_size;
649       return true;
650     case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
651       *params = static_state_.int_state.max_fragment_uniform_vectors;
652       return true;
653     case GL_MAX_RENDERBUFFER_SIZE:
654       *params = static_state_.int_state.max_renderbuffer_size;
655       return true;
656     case GL_MAX_TEXTURE_IMAGE_UNITS:
657       *params = static_state_.int_state.max_texture_image_units;
658       return true;
659     case GL_MAX_TEXTURE_SIZE:
660       *params = static_state_.int_state.max_texture_size;
661       return true;
662     case GL_MAX_VARYING_VECTORS:
663       *params = static_state_.int_state.max_varying_vectors;
664       return true;
665     case GL_MAX_VERTEX_ATTRIBS:
666       *params = static_state_.int_state.max_vertex_attribs;
667       return true;
668     case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
669       *params = static_state_.int_state.max_vertex_texture_image_units;
670       return true;
671     case GL_MAX_VERTEX_UNIFORM_VECTORS:
672       *params = static_state_.int_state.max_vertex_uniform_vectors;
673       return true;
674     case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
675       *params = static_state_.int_state.num_compressed_texture_formats;
676       return true;
677     case GL_NUM_SHADER_BINARY_FORMATS:
678       *params = static_state_.int_state.num_shader_binary_formats;
679       return true;
680     case GL_ARRAY_BUFFER_BINDING:
681       if (share_group_->bind_generates_resource()) {
682         *params = bound_array_buffer_id_;
683         return true;
684       }
685       return false;
686     case GL_ELEMENT_ARRAY_BUFFER_BINDING:
687       if (share_group_->bind_generates_resource()) {
688         *params =
689             vertex_array_object_manager_->bound_element_array_buffer();
690         return true;
691       }
692       return false;
693     case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
694       *params = bound_pixel_pack_transfer_buffer_id_;
695       return true;
696     case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
697       *params = bound_pixel_unpack_transfer_buffer_id_;
698       return true;
699     case GL_ACTIVE_TEXTURE:
700       *params = active_texture_unit_ + GL_TEXTURE0;
701       return true;
702     case GL_TEXTURE_BINDING_2D:
703       if (share_group_->bind_generates_resource()) {
704         *params = texture_units_[active_texture_unit_].bound_texture_2d;
705         return true;
706       }
707       return false;
708     case GL_TEXTURE_BINDING_CUBE_MAP:
709       if (share_group_->bind_generates_resource()) {
710         *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
711         return true;
712       }
713       return false;
714     case GL_TEXTURE_BINDING_EXTERNAL_OES:
715       if (share_group_->bind_generates_resource()) {
716         *params =
717             texture_units_[active_texture_unit_].bound_texture_external_oes;
718         return true;
719       }
720       return false;
721     case GL_FRAMEBUFFER_BINDING:
722       if (share_group_->bind_generates_resource()) {
723         *params = bound_framebuffer_;
724         return true;
725       }
726       return false;
727     case GL_READ_FRAMEBUFFER_BINDING:
728       if (IsChromiumFramebufferMultisampleAvailable() &&
729           share_group_->bind_generates_resource()) {
730         *params = bound_read_framebuffer_;
731         return true;
732       }
733       return false;
734     case GL_RENDERBUFFER_BINDING:
735       if (share_group_->bind_generates_resource()) {
736         *params = bound_renderbuffer_;
737         return true;
738       }
739       return false;
740     default:
741       return false;
742   }
743 }
744 
GetBooleanvHelper(GLenum pname,GLboolean * params)745 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
746   // TODO(gman): Make this handle pnames that return more than 1 value.
747   GLint value;
748   if (!GetHelper(pname, &value)) {
749     return false;
750   }
751   *params = static_cast<GLboolean>(value);
752   return true;
753 }
754 
GetFloatvHelper(GLenum pname,GLfloat * params)755 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
756   // TODO(gman): Make this handle pnames that return more than 1 value.
757   GLint value;
758   if (!GetHelper(pname, &value)) {
759     return false;
760   }
761   *params = static_cast<GLfloat>(value);
762   return true;
763 }
764 
GetIntegervHelper(GLenum pname,GLint * params)765 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
766   return GetHelper(pname, params);
767 }
768 
GetMaxValueInBufferCHROMIUMHelper(GLuint buffer_id,GLsizei count,GLenum type,GLuint offset)769 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
770     GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
771   typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
772   Result* result = GetResultAs<Result*>();
773   if (!result) {
774     return 0;
775   }
776   *result = 0;
777   helper_->GetMaxValueInBufferCHROMIUM(
778       buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
779   WaitForCmd();
780   return *result;
781 }
782 
GetMaxValueInBufferCHROMIUM(GLuint buffer_id,GLsizei count,GLenum type,GLuint offset)783 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
784     GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
785   GPU_CLIENT_SINGLE_THREAD_CHECK();
786   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
787                  << buffer_id << ", " << count << ", "
788                  << GLES2Util::GetStringGetMaxIndexType(type)
789                  << ", " << offset << ")");
790   GLuint result = GetMaxValueInBufferCHROMIUMHelper(
791       buffer_id, count, type, offset);
792   GPU_CLIENT_LOG("returned " << result);
793   CheckGLError();
794   return result;
795 }
796 
RestoreElementAndArrayBuffers(bool restore)797 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
798   if (restore) {
799     RestoreArrayBuffer(restore);
800     // Restore the element array binding.
801     // We only need to restore it if it wasn't a client side array.
802     if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
803       helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
804     }
805   }
806 }
807 
RestoreArrayBuffer(bool restore)808 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
809   if (restore) {
810     // Restore the user's current binding.
811     helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
812   }
813 }
814 
DrawElements(GLenum mode,GLsizei count,GLenum type,const void * indices)815 void GLES2Implementation::DrawElements(
816     GLenum mode, GLsizei count, GLenum type, const void* indices) {
817   GPU_CLIENT_SINGLE_THREAD_CHECK();
818   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
819       << GLES2Util::GetStringDrawMode(mode) << ", "
820       << count << ", "
821       << GLES2Util::GetStringIndexType(type) << ", "
822       << static_cast<const void*>(indices) << ")");
823   if (count < 0) {
824     SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
825     return;
826   }
827   if (count == 0) {
828     return;
829   }
830   GLuint offset = 0;
831   bool simulated = false;
832   if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
833       "glDrawElements", this, helper_, count, type, 0, indices,
834       &offset, &simulated)) {
835     return;
836   }
837   helper_->DrawElements(mode, count, type, offset);
838   RestoreElementAndArrayBuffers(simulated);
839   CheckGLError();
840 }
841 
Flush()842 void GLES2Implementation::Flush() {
843   GPU_CLIENT_SINGLE_THREAD_CHECK();
844   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
845   // Insert the cmd to call glFlush
846   helper_->Flush();
847   // Flush our command buffer
848   // (tell the service to execute up to the flush cmd.)
849   helper_->CommandBufferHelper::Flush();
850   if (!surface_visible_ && free_everything_when_invisible_)
851     FreeEverything();
852 }
853 
ShallowFlushCHROMIUM()854 void GLES2Implementation::ShallowFlushCHROMIUM() {
855   GPU_CLIENT_SINGLE_THREAD_CHECK();
856   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
857   // Flush our command buffer
858   // (tell the service to execute up to the flush cmd.)
859   helper_->CommandBufferHelper::Flush();
860   // TODO(piman): Add the FreeEverything() logic here.
861 }
862 
Finish()863 void GLES2Implementation::Finish() {
864   GPU_CLIENT_SINGLE_THREAD_CHECK();
865   FinishHelper();
866   if (!surface_visible_ && free_everything_when_invisible_)
867     FreeEverything();
868 }
869 
ShallowFinishCHROMIUM()870 void GLES2Implementation::ShallowFinishCHROMIUM() {
871   GPU_CLIENT_SINGLE_THREAD_CHECK();
872   // Flush our command buffer (tell the service to execute up to the flush cmd
873   // and don't return until it completes).
874   helper_->CommandBufferHelper::Finish();
875 }
876 
MustBeContextLost()877 bool GLES2Implementation::MustBeContextLost() {
878   bool context_lost = helper_->IsContextLost();
879   if (!context_lost) {
880     WaitForCmd();
881     context_lost = helper_->IsContextLost();
882   }
883   CHECK(context_lost);
884   return context_lost;
885 }
886 
FinishHelper()887 void GLES2Implementation::FinishHelper() {
888   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
889   TRACE_EVENT0("gpu", "GLES2::Finish");
890   // Insert the cmd to call glFinish
891   helper_->Finish();
892   // Finish our command buffer
893   // (tell the service to execute up to the Finish cmd and wait for it to
894   // execute.)
895   helper_->CommandBufferHelper::Finish();
896 }
897 
SwapBuffers()898 void GLES2Implementation::SwapBuffers() {
899   GPU_CLIENT_SINGLE_THREAD_CHECK();
900   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
901   // TODO(piman): Strictly speaking we'd want to insert the token after the
902   // swap, but the state update with the updated token might not have happened
903   // by the time the SwapBuffer callback gets called, forcing us to synchronize
904   // with the GPU process more than needed. So instead, make it happen before.
905   // All it means is that we could be slightly looser on the kMaxSwapBuffers
906   // semantics if the client doesn't use the callback mechanism, and by chance
907   // the scheduler yields between the InsertToken and the SwapBuffers.
908   swap_buffers_tokens_.push(helper_->InsertToken());
909   helper_->SwapBuffers();
910   helper_->CommandBufferHelper::Flush();
911   // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
912   // compensate for TODO above.
913   if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
914     helper_->WaitForToken(swap_buffers_tokens_.front());
915     swap_buffers_tokens_.pop();
916   }
917 }
918 
GenSharedIdsCHROMIUM(GLuint namespace_id,GLuint id_offset,GLsizei n,GLuint * ids)919 void GLES2Implementation::GenSharedIdsCHROMIUM(
920   GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
921   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
922       << namespace_id << ", " << id_offset << ", " << n << ", " <<
923       static_cast<void*>(ids) << ")");
924   TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
925   GLsizei num = n;
926   GLuint* dst = ids;
927   while (num) {
928     ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
929     if (!id_buffer.valid()) {
930       return;
931     }
932     helper_->GenSharedIdsCHROMIUM(
933         namespace_id, id_offset, id_buffer.num_elements(),
934         id_buffer.shm_id(), id_buffer.offset());
935     WaitForCmd();
936     memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
937     num -= id_buffer.num_elements();
938     dst += id_buffer.num_elements();
939   }
940   GPU_CLIENT_LOG_CODE_BLOCK({
941     for (GLsizei i = 0; i < n; ++i) {
942       GPU_CLIENT_LOG("  " << i << ": " << namespace_id << ", " << ids[i]);
943     }
944   });
945 }
946 
DeleteSharedIdsCHROMIUM(GLuint namespace_id,GLsizei n,const GLuint * ids)947 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
948     GLuint namespace_id, GLsizei n, const GLuint* ids) {
949   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
950       << namespace_id << ", " << n << ", "
951       << static_cast<const void*>(ids) << ")");
952   GPU_CLIENT_LOG_CODE_BLOCK({
953     for (GLsizei i = 0; i < n; ++i) {
954       GPU_CLIENT_LOG("  " << i << ": " << namespace_id << ", "  << ids[i]);
955     }
956   });
957   TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
958   while (n) {
959     ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
960     if (!id_buffer.valid()) {
961       return;
962     }
963     memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
964     helper_->DeleteSharedIdsCHROMIUM(
965         namespace_id, id_buffer.num_elements(),
966         id_buffer.shm_id(), id_buffer.offset());
967     WaitForCmd();
968     n -= id_buffer.num_elements();
969     ids += id_buffer.num_elements();
970   }
971 }
972 
RegisterSharedIdsCHROMIUM(GLuint namespace_id,GLsizei n,const GLuint * ids)973 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
974     GLuint namespace_id, GLsizei n, const GLuint* ids) {
975   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
976      << namespace_id << ", " << n << ", "
977      << static_cast<const void*>(ids) << ")");
978   GPU_CLIENT_LOG_CODE_BLOCK({
979     for (GLsizei i = 0; i < n; ++i) {
980       GPU_CLIENT_LOG("  " << i << ": "  << namespace_id << ", " << ids[i]);
981     }
982   });
983   TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
984   while (n) {
985     ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
986     if (!id_buffer.valid()) {
987       return;
988     }
989     memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
990     helper_->RegisterSharedIdsCHROMIUM(
991         namespace_id, id_buffer.num_elements(),
992         id_buffer.shm_id(), id_buffer.offset());
993     WaitForCmd();
994     n -= id_buffer.num_elements();
995     ids += id_buffer.num_elements();
996   }
997 }
998 
BindAttribLocation(GLuint program,GLuint index,const char * name)999 void GLES2Implementation::BindAttribLocation(
1000   GLuint program, GLuint index, const char* name) {
1001   GPU_CLIENT_SINGLE_THREAD_CHECK();
1002   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1003       << program << ", " << index << ", " << name << ")");
1004   SetBucketAsString(kResultBucketId, name);
1005   helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1006   helper_->SetBucketSize(kResultBucketId, 0);
1007   CheckGLError();
1008 }
1009 
BindUniformLocationCHROMIUM(GLuint program,GLint location,const char * name)1010 void GLES2Implementation::BindUniformLocationCHROMIUM(
1011   GLuint program, GLint location, const char* name) {
1012   GPU_CLIENT_SINGLE_THREAD_CHECK();
1013   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1014       << program << ", " << location << ", " << name << ")");
1015   SetBucketAsString(kResultBucketId, name);
1016   helper_->BindUniformLocationCHROMIUMBucket(
1017       program, location, kResultBucketId);
1018   helper_->SetBucketSize(kResultBucketId, 0);
1019   CheckGLError();
1020 }
1021 
GetVertexAttribPointerv(GLuint index,GLenum pname,void ** ptr)1022 void GLES2Implementation::GetVertexAttribPointerv(
1023     GLuint index, GLenum pname, void** ptr) {
1024   GPU_CLIENT_SINGLE_THREAD_CHECK();
1025   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1026       << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1027       << static_cast<void*>(ptr) << ")");
1028   GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1029   if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1030     TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1031     typedef cmds::GetVertexAttribPointerv::Result Result;
1032     Result* result = GetResultAs<Result*>();
1033     if (!result) {
1034       return;
1035     }
1036     result->SetNumResults(0);
1037     helper_->GetVertexAttribPointerv(
1038       index, pname, GetResultShmId(), GetResultShmOffset());
1039     WaitForCmd();
1040     result->CopyResult(ptr);
1041     GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1042   }
1043   GPU_CLIENT_LOG_CODE_BLOCK({
1044     for (int32 i = 0; i < num_results; ++i) {
1045       GPU_CLIENT_LOG("  " << i << ": " << ptr[i]);
1046     }
1047   });
1048   CheckGLError();
1049 }
1050 
DeleteProgramHelper(GLuint program)1051 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1052   if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1053       this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1054     SetGLError(
1055         GL_INVALID_VALUE,
1056         "glDeleteProgram", "id not created by this context.");
1057     return false;
1058   }
1059   if (program == current_program_) {
1060     current_program_ = 0;
1061   }
1062   return true;
1063 }
1064 
DeleteProgramStub(GLsizei n,const GLuint * programs)1065 void GLES2Implementation::DeleteProgramStub(
1066     GLsizei n, const GLuint* programs) {
1067   DCHECK_EQ(1, n);
1068   share_group_->program_info_manager()->DeleteInfo(programs[0]);
1069   helper_->DeleteProgram(programs[0]);
1070 }
1071 
DeleteShaderHelper(GLuint shader)1072 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1073   if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1074       this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1075     SetGLError(
1076         GL_INVALID_VALUE,
1077         "glDeleteShader", "id not created by this context.");
1078     return false;
1079   }
1080   return true;
1081 }
1082 
DeleteShaderStub(GLsizei n,const GLuint * shaders)1083 void GLES2Implementation::DeleteShaderStub(
1084     GLsizei n, const GLuint* shaders) {
1085   DCHECK_EQ(1, n);
1086   share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1087   helper_->DeleteShader(shaders[0]);
1088 }
1089 
1090 
GetAttribLocationHelper(GLuint program,const char * name)1091 GLint GLES2Implementation::GetAttribLocationHelper(
1092     GLuint program, const char* name) {
1093   typedef cmds::GetAttribLocationBucket::Result Result;
1094   Result* result = GetResultAs<Result*>();
1095   if (!result) {
1096     return -1;
1097   }
1098   *result = -1;
1099   SetBucketAsCString(kResultBucketId, name);
1100   helper_->GetAttribLocationBucket(
1101       program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1102   WaitForCmd();
1103   helper_->SetBucketSize(kResultBucketId, 0);
1104   return *result;
1105 }
1106 
GetAttribLocation(GLuint program,const char * name)1107 GLint GLES2Implementation::GetAttribLocation(
1108     GLuint program, const char* name) {
1109   GPU_CLIENT_SINGLE_THREAD_CHECK();
1110   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1111       << ", " << name << ")");
1112   TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1113   GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1114       this, program, name);
1115   GPU_CLIENT_LOG("returned " << loc);
1116   CheckGLError();
1117   return loc;
1118 }
1119 
GetUniformLocationHelper(GLuint program,const char * name)1120 GLint GLES2Implementation::GetUniformLocationHelper(
1121     GLuint program, const char* name) {
1122   typedef cmds::GetUniformLocationBucket::Result Result;
1123   Result* result = GetResultAs<Result*>();
1124   if (!result) {
1125     return -1;
1126   }
1127   *result = -1;
1128   SetBucketAsCString(kResultBucketId, name);
1129   helper_->GetUniformLocationBucket(program, kResultBucketId,
1130                                     GetResultShmId(), GetResultShmOffset());
1131   WaitForCmd();
1132   helper_->SetBucketSize(kResultBucketId, 0);
1133   return *result;
1134 }
1135 
GetUniformLocation(GLuint program,const char * name)1136 GLint GLES2Implementation::GetUniformLocation(
1137     GLuint program, const char* name) {
1138   GPU_CLIENT_SINGLE_THREAD_CHECK();
1139   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1140       << ", " << name << ")");
1141   TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1142   GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1143       this, program, name);
1144   GPU_CLIENT_LOG("returned " << loc);
1145   CheckGLError();
1146   return loc;
1147 }
1148 
UseProgram(GLuint program)1149 void GLES2Implementation::UseProgram(GLuint program) {
1150   GPU_CLIENT_SINGLE_THREAD_CHECK();
1151   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
1152   if (current_program_ != program) {
1153     current_program_ = program;
1154     helper_->UseProgram(program);
1155   }
1156   CheckGLError();
1157 }
1158 
GetProgramivHelper(GLuint program,GLenum pname,GLint * params)1159 bool GLES2Implementation::GetProgramivHelper(
1160     GLuint program, GLenum pname, GLint* params) {
1161   bool got_value = share_group_->program_info_manager()->GetProgramiv(
1162       this, program, pname, params);
1163   GPU_CLIENT_LOG_CODE_BLOCK({
1164     if (got_value) {
1165       GPU_CLIENT_LOG("  0: " << *params);
1166     }
1167   });
1168   return got_value;
1169 }
1170 
LinkProgram(GLuint program)1171 void GLES2Implementation::LinkProgram(GLuint program) {
1172   GPU_CLIENT_SINGLE_THREAD_CHECK();
1173   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1174   helper_->LinkProgram(program);
1175   share_group_->program_info_manager()->CreateInfo(program);
1176   CheckGLError();
1177 }
1178 
ShaderBinary(GLsizei n,const GLuint * shaders,GLenum binaryformat,const void * binary,GLsizei length)1179 void GLES2Implementation::ShaderBinary(
1180     GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1181     GLsizei length) {
1182   GPU_CLIENT_SINGLE_THREAD_CHECK();
1183   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1184       << static_cast<const void*>(shaders) << ", "
1185       << GLES2Util::GetStringEnum(binaryformat) << ", "
1186       << static_cast<const void*>(binary) << ", "
1187       << length << ")");
1188   if (n < 0) {
1189     SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1190     return;
1191   }
1192   if (length < 0) {
1193     SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1194     return;
1195   }
1196   // TODO(gman): ShaderBinary should use buckets.
1197   unsigned int shader_id_size = n * sizeof(*shaders);
1198   ScopedTransferBufferArray<GLint> buffer(
1199       shader_id_size + length, helper_, transfer_buffer_);
1200   if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1201     SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1202     return;
1203   }
1204   void* shader_ids = buffer.elements();
1205   void* shader_data = buffer.elements() + shader_id_size;
1206   memcpy(shader_ids, shaders, shader_id_size);
1207   memcpy(shader_data, binary, length);
1208   helper_->ShaderBinary(
1209       n,
1210       buffer.shm_id(),
1211       buffer.offset(),
1212       binaryformat,
1213       buffer.shm_id(),
1214       buffer.offset() + shader_id_size,
1215       length);
1216   CheckGLError();
1217 }
1218 
PixelStorei(GLenum pname,GLint param)1219 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1220   GPU_CLIENT_SINGLE_THREAD_CHECK();
1221   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1222       << GLES2Util::GetStringPixelStore(pname) << ", "
1223       << param << ")");
1224   switch (pname) {
1225     case GL_PACK_ALIGNMENT:
1226         pack_alignment_ = param;
1227         break;
1228     case GL_UNPACK_ALIGNMENT:
1229         unpack_alignment_ = param;
1230         break;
1231     case GL_UNPACK_ROW_LENGTH:
1232         unpack_row_length_ = param;
1233         return;
1234     case GL_UNPACK_SKIP_ROWS:
1235         unpack_skip_rows_ = param;
1236         return;
1237     case GL_UNPACK_SKIP_PIXELS:
1238         unpack_skip_pixels_ = param;
1239         return;
1240     case GL_UNPACK_FLIP_Y_CHROMIUM:
1241         unpack_flip_y_ = (param != 0);
1242         break;
1243     case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1244         pack_reverse_row_order_ =
1245             IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1246         break;
1247     default:
1248         break;
1249   }
1250   helper_->PixelStorei(pname, param);
1251   CheckGLError();
1252 }
1253 
1254 
VertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const void * ptr)1255 void GLES2Implementation::VertexAttribPointer(
1256     GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1257     const void* ptr) {
1258   GPU_CLIENT_SINGLE_THREAD_CHECK();
1259   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1260       << index << ", "
1261       << size << ", "
1262       << GLES2Util::GetStringVertexAttribType(type) << ", "
1263       << GLES2Util::GetStringBool(normalized) << ", "
1264       << stride << ", "
1265       << static_cast<const void*>(ptr) << ")");
1266   // Record the info on the client side.
1267   if (!vertex_array_object_manager_->SetAttribPointer(
1268       bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1269     SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1270                "client side arrays are not allowed in vertex array objects.");
1271     return;
1272   }
1273 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1274   if (bound_array_buffer_id_ != 0) {
1275     // Only report NON client side buffers to the service.
1276     helper_->VertexAttribPointer(index, size, type, normalized, stride,
1277                                  ToGLuint(ptr));
1278   }
1279 #else  // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1280   helper_->VertexAttribPointer(index, size, type, normalized, stride,
1281                                ToGLuint(ptr));
1282 #endif  // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1283   CheckGLError();
1284 }
1285 
VertexAttribDivisorANGLE(GLuint index,GLuint divisor)1286 void GLES2Implementation::VertexAttribDivisorANGLE(
1287     GLuint index, GLuint divisor) {
1288   GPU_CLIENT_SINGLE_THREAD_CHECK();
1289   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1290       << index << ", "
1291       << divisor << ") ");
1292   // Record the info on the client side.
1293   vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1294   helper_->VertexAttribDivisorANGLE(index, divisor);
1295   CheckGLError();
1296 }
1297 
ShaderSource(GLuint shader,GLsizei count,const GLchar * const * source,const GLint * length)1298 void GLES2Implementation::ShaderSource(
1299     GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1300   GPU_CLIENT_SINGLE_THREAD_CHECK();
1301   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1302       << shader << ", " << count << ", "
1303       << static_cast<const void*>(source) << ", "
1304       << static_cast<const void*>(length) << ")");
1305   GPU_CLIENT_LOG_CODE_BLOCK({
1306     for (GLsizei ii = 0; ii < count; ++ii) {
1307       if (source[ii]) {
1308         if (length && length[ii] >= 0) {
1309           std::string str(source[ii], length[ii]);
1310           GPU_CLIENT_LOG("  " << ii << ": ---\n" << str << "\n---");
1311         } else {
1312           GPU_CLIENT_LOG("  " << ii << ": ---\n" << source[ii] << "\n---");
1313         }
1314       } else {
1315         GPU_CLIENT_LOG("  " << ii << ": NULL");
1316       }
1317     }
1318   });
1319   if (count < 0) {
1320     SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1321     return;
1322   }
1323   if (shader == 0) {
1324     SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1325     return;
1326   }
1327 
1328   // Compute the total size.
1329   uint32 total_size = 1;
1330   for (GLsizei ii = 0; ii < count; ++ii) {
1331     if (source[ii]) {
1332       total_size += (length && length[ii] >= 0) ?
1333           static_cast<size_t>(length[ii]) : strlen(source[ii]);
1334     }
1335   }
1336 
1337   // Concatenate all the strings in to a bucket on the service.
1338   helper_->SetBucketSize(kResultBucketId, total_size);
1339   uint32 offset = 0;
1340   for (GLsizei ii = 0; ii <= count; ++ii) {
1341     const char* src = ii < count ? source[ii] : "";
1342     if (src) {
1343       uint32 size = ii < count ?
1344           (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1345       while (size) {
1346         ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1347         if (!buffer.valid()) {
1348           return;
1349         }
1350         memcpy(buffer.address(), src, buffer.size());
1351         helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1352                                buffer.shm_id(), buffer.offset());
1353         offset += buffer.size();
1354         src += buffer.size();
1355         size -= buffer.size();
1356       }
1357     }
1358   }
1359 
1360   DCHECK_EQ(total_size, offset);
1361 
1362   helper_->ShaderSourceBucket(shader, kResultBucketId);
1363   helper_->SetBucketSize(kResultBucketId, 0);
1364   CheckGLError();
1365 }
1366 
BufferDataHelper(GLenum target,GLsizeiptr size,const void * data,GLenum usage)1367 void GLES2Implementation::BufferDataHelper(
1368     GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1369   if (size < 0) {
1370     SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1371     return;
1372   }
1373 
1374   GLuint buffer_id;
1375   if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1376     if (!buffer_id) {
1377       return;
1378     }
1379 
1380     BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1381     if (buffer) {
1382       // Free buffer memory, pending the passage of a token.
1383       buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1384 
1385       // Remove old buffer.
1386       buffer_tracker_->RemoveBuffer(buffer_id);
1387     }
1388 
1389     // Create new buffer.
1390     buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1391     DCHECK(buffer);
1392     if (buffer->address() && data)
1393       memcpy(buffer->address(), data, size);
1394     return;
1395   }
1396 
1397   if (size == 0) {
1398     return;
1399   }
1400 
1401   // If there is no data just send BufferData
1402   if (!data) {
1403     helper_->BufferData(target, size, 0, 0, usage);
1404     return;
1405   }
1406 
1407   // See if we can send all at once.
1408   ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1409   if (!buffer.valid()) {
1410     return;
1411   }
1412 
1413   if (buffer.size() >= static_cast<unsigned int>(size)) {
1414     memcpy(buffer.address(), data, size);
1415     helper_->BufferData(
1416         target,
1417         size,
1418         buffer.shm_id(),
1419         buffer.offset(),
1420         usage);
1421     return;
1422   }
1423 
1424   // Make the buffer with BufferData then send via BufferSubData
1425   helper_->BufferData(target, size, 0, 0, usage);
1426   BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1427   CheckGLError();
1428 }
1429 
BufferData(GLenum target,GLsizeiptr size,const void * data,GLenum usage)1430 void GLES2Implementation::BufferData(
1431     GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1432   GPU_CLIENT_SINGLE_THREAD_CHECK();
1433   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1434       << GLES2Util::GetStringBufferTarget(target) << ", "
1435       << size << ", "
1436       << static_cast<const void*>(data) << ", "
1437       << GLES2Util::GetStringBufferUsage(usage) << ")");
1438   BufferDataHelper(target, size, data, usage);
1439   CheckGLError();
1440 }
1441 
BufferSubDataHelper(GLenum target,GLintptr offset,GLsizeiptr size,const void * data)1442 void GLES2Implementation::BufferSubDataHelper(
1443     GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1444   if (size == 0) {
1445     return;
1446   }
1447 
1448   if (size < 0) {
1449     SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1450     return;
1451   }
1452 
1453   GLuint buffer_id;
1454   if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1455     if (!buffer_id) {
1456       return;
1457     }
1458     BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1459     if (!buffer) {
1460       SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1461       return;
1462     }
1463 
1464     int32 end = 0;
1465     int32 buffer_size = buffer->size();
1466     if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1467       SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1468       return;
1469     }
1470 
1471     if (buffer->address() && data)
1472       memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1473     return;
1474   }
1475 
1476   ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1477   BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1478 }
1479 
BufferSubDataHelperImpl(GLenum target,GLintptr offset,GLsizeiptr size,const void * data,ScopedTransferBufferPtr * buffer)1480 void GLES2Implementation::BufferSubDataHelperImpl(
1481     GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1482     ScopedTransferBufferPtr* buffer) {
1483   DCHECK(buffer);
1484   DCHECK_GT(size, 0);
1485 
1486   const int8* source = static_cast<const int8*>(data);
1487   while (size) {
1488     if (!buffer->valid() || buffer->size() == 0) {
1489       buffer->Reset(size);
1490       if (!buffer->valid()) {
1491         return;
1492       }
1493     }
1494     memcpy(buffer->address(), source, buffer->size());
1495     helper_->BufferSubData(
1496         target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1497     offset += buffer->size();
1498     source += buffer->size();
1499     size -= buffer->size();
1500     buffer->Release();
1501   }
1502 }
1503 
BufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const void * data)1504 void GLES2Implementation::BufferSubData(
1505     GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1506   GPU_CLIENT_SINGLE_THREAD_CHECK();
1507   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1508       << GLES2Util::GetStringBufferTarget(target) << ", "
1509       << offset << ", " << size << ", "
1510       << static_cast<const void*>(data) << ")");
1511   BufferSubDataHelper(target, offset, size, data);
1512   CheckGLError();
1513 }
1514 
GetBoundPixelTransferBuffer(GLenum target,const char * function_name,GLuint * buffer_id)1515 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1516     GLenum target,
1517     const char* function_name,
1518     GLuint* buffer_id) {
1519   *buffer_id = 0;
1520 
1521   switch (target) {
1522     case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1523       *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1524       break;
1525     case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1526       *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1527       break;
1528     default:
1529       // Unknown target
1530       return false;
1531   }
1532   if (!*buffer_id) {
1533     SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1534   }
1535   return true;
1536 }
1537 
1538 BufferTracker::Buffer*
GetBoundPixelUnpackTransferBufferIfValid(GLuint buffer_id,const char * function_name,GLuint offset,GLsizei size)1539 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1540     GLuint buffer_id,
1541     const char* function_name,
1542     GLuint offset, GLsizei size)
1543 {
1544   DCHECK(buffer_id);
1545   BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1546   if (!buffer) {
1547     SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1548     return NULL;
1549   }
1550   if (buffer->mapped()) {
1551     SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1552     return NULL;
1553   }
1554   if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1555     SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1556     return NULL;
1557   }
1558   return buffer;
1559 }
1560 
CompressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLsizei image_size,const void * data)1561 void GLES2Implementation::CompressedTexImage2D(
1562     GLenum target, GLint level, GLenum internalformat, GLsizei width,
1563     GLsizei height, GLint border, GLsizei image_size, const void* data) {
1564   GPU_CLIENT_SINGLE_THREAD_CHECK();
1565   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1566       << GLES2Util::GetStringTextureTarget(target) << ", "
1567       << level << ", "
1568       << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1569       << width << ", " << height << ", " << border << ", "
1570       << image_size << ", "
1571       << static_cast<const void*>(data) << ")");
1572   if (width < 0 || height < 0 || level < 0) {
1573     SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1574     return;
1575   }
1576   if (height == 0 || width == 0) {
1577     return;
1578   }
1579   // If there's a pixel unpack buffer bound use it when issuing
1580   // CompressedTexImage2D.
1581   if (bound_pixel_unpack_transfer_buffer_id_) {
1582     GLuint offset = ToGLuint(data);
1583     BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1584         bound_pixel_unpack_transfer_buffer_id_,
1585         "glCompressedTexImage2D", offset, image_size);
1586     if (buffer && buffer->shm_id() != -1) {
1587       helper_->CompressedTexImage2D(
1588           target, level, internalformat, width, height, border, image_size,
1589           buffer->shm_id(), buffer->shm_offset() + offset);
1590       buffer->set_transfer_ready_token(helper_->InsertToken());
1591     }
1592     return;
1593   }
1594   SetBucketContents(kResultBucketId, data, image_size);
1595   helper_->CompressedTexImage2DBucket(
1596       target, level, internalformat, width, height, border, kResultBucketId);
1597   // Free the bucket. This is not required but it does free up the memory.
1598   // and we don't have to wait for the result so from the client's perspective
1599   // it's cheap.
1600   helper_->SetBucketSize(kResultBucketId, 0);
1601   CheckGLError();
1602 }
1603 
CompressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei image_size,const void * data)1604 void GLES2Implementation::CompressedTexSubImage2D(
1605     GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1606     GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1607   GPU_CLIENT_SINGLE_THREAD_CHECK();
1608   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1609       << GLES2Util::GetStringTextureTarget(target) << ", "
1610       << level << ", "
1611       << xoffset << ", " << yoffset << ", "
1612       << width << ", " << height << ", "
1613       << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1614       << image_size << ", "
1615       << static_cast<const void*>(data) << ")");
1616   if (width < 0 || height < 0 || level < 0) {
1617     SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1618     return;
1619   }
1620   // If there's a pixel unpack buffer bound use it when issuing
1621   // CompressedTexSubImage2D.
1622   if (bound_pixel_unpack_transfer_buffer_id_) {
1623     GLuint offset = ToGLuint(data);
1624     BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1625         bound_pixel_unpack_transfer_buffer_id_,
1626         "glCompressedTexSubImage2D", offset, image_size);
1627     if (buffer && buffer->shm_id() != -1) {
1628       helper_->CompressedTexSubImage2D(
1629           target, level, xoffset, yoffset, width, height, format, image_size,
1630           buffer->shm_id(), buffer->shm_offset() + offset);
1631       buffer->set_transfer_ready_token(helper_->InsertToken());
1632       CheckGLError();
1633     }
1634     return;
1635   }
1636   SetBucketContents(kResultBucketId, data, image_size);
1637   helper_->CompressedTexSubImage2DBucket(
1638       target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1639   // Free the bucket. This is not required but it does free up the memory.
1640   // and we don't have to wait for the result so from the client's perspective
1641   // it's cheap.
1642   helper_->SetBucketSize(kResultBucketId, 0);
1643   CheckGLError();
1644 }
1645 
1646 namespace {
1647 
CopyRectToBuffer(const void * pixels,uint32 height,uint32 unpadded_row_size,uint32 pixels_padded_row_size,bool flip_y,void * buffer,uint32 buffer_padded_row_size)1648 void CopyRectToBuffer(
1649     const void* pixels,
1650     uint32 height,
1651     uint32 unpadded_row_size,
1652     uint32 pixels_padded_row_size,
1653     bool flip_y,
1654     void* buffer,
1655     uint32 buffer_padded_row_size) {
1656   const int8* source = static_cast<const int8*>(pixels);
1657   int8* dest = static_cast<int8*>(buffer);
1658   if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1659     if (flip_y) {
1660       dest += buffer_padded_row_size * (height - 1);
1661     }
1662     // the last row is copied unpadded at the end
1663     for (; height > 1; --height) {
1664       memcpy(dest, source, buffer_padded_row_size);
1665       if (flip_y) {
1666         dest -= buffer_padded_row_size;
1667       } else {
1668         dest += buffer_padded_row_size;
1669       }
1670       source += pixels_padded_row_size;
1671     }
1672     memcpy(dest, source, unpadded_row_size);
1673   } else {
1674     uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1675     memcpy(dest, source, size);
1676   }
1677 }
1678 
1679 }  // anonymous namespace
1680 
TexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)1681 void GLES2Implementation::TexImage2D(
1682     GLenum target, GLint level, GLint internalformat, GLsizei width,
1683     GLsizei height, GLint border, GLenum format, GLenum type,
1684     const void* pixels) {
1685   GPU_CLIENT_SINGLE_THREAD_CHECK();
1686   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1687       << GLES2Util::GetStringTextureTarget(target) << ", "
1688       << level << ", "
1689       << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1690       << width << ", " << height << ", " << border << ", "
1691       << GLES2Util::GetStringTextureFormat(format) << ", "
1692       << GLES2Util::GetStringPixelType(type) << ", "
1693       << static_cast<const void*>(pixels) << ")");
1694   if (level < 0 || height < 0 || width < 0) {
1695     SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1696     return;
1697   }
1698   uint32 size;
1699   uint32 unpadded_row_size;
1700   uint32 padded_row_size;
1701   if (!GLES2Util::ComputeImageDataSizes(
1702           width, height, format, type, unpack_alignment_, &size,
1703           &unpadded_row_size, &padded_row_size)) {
1704     SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1705     return;
1706   }
1707 
1708   // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1709   if (bound_pixel_unpack_transfer_buffer_id_) {
1710     GLuint offset = ToGLuint(pixels);
1711     BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1712         bound_pixel_unpack_transfer_buffer_id_,
1713         "glTexImage2D", offset, size);
1714     if (buffer && buffer->shm_id() != -1) {
1715       helper_->TexImage2D(
1716           target, level, internalformat, width, height, border, format, type,
1717           buffer->shm_id(), buffer->shm_offset() + offset);
1718       buffer->set_transfer_ready_token(helper_->InsertToken());
1719       CheckGLError();
1720     }
1721     return;
1722   }
1723 
1724   // If there's no data just issue TexImage2D
1725   if (!pixels) {
1726     helper_->TexImage2D(
1727        target, level, internalformat, width, height, border, format, type,
1728        0, 0);
1729     CheckGLError();
1730     return;
1731   }
1732 
1733   // compute the advance bytes per row for the src pixels
1734   uint32 src_padded_row_size;
1735   if (unpack_row_length_ > 0) {
1736     if (!GLES2Util::ComputeImagePaddedRowSize(
1737         unpack_row_length_, format, type, unpack_alignment_,
1738         &src_padded_row_size)) {
1739       SetGLError(
1740           GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1741       return;
1742     }
1743   } else {
1744     src_padded_row_size = padded_row_size;
1745   }
1746 
1747   // advance pixels pointer past the skip rows and skip pixels
1748   pixels = reinterpret_cast<const int8*>(pixels) +
1749       unpack_skip_rows_ * src_padded_row_size;
1750   if (unpack_skip_pixels_) {
1751     uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1752     pixels = reinterpret_cast<const int8*>(pixels) +
1753         unpack_skip_pixels_ * group_size;
1754   }
1755 
1756   // Check if we can send it all at once.
1757   ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1758   if (!buffer.valid()) {
1759     return;
1760   }
1761 
1762   if (buffer.size() >= size) {
1763     CopyRectToBuffer(
1764         pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1765         buffer.address(), padded_row_size);
1766     helper_->TexImage2D(
1767         target, level, internalformat, width, height, border, format, type,
1768         buffer.shm_id(), buffer.offset());
1769     CheckGLError();
1770     return;
1771   }
1772 
1773   // No, so send it using TexSubImage2D.
1774   helper_->TexImage2D(
1775      target, level, internalformat, width, height, border, format, type,
1776      0, 0);
1777   TexSubImage2DImpl(
1778       target, level, 0, 0, width, height, format, type, unpadded_row_size,
1779       pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1780   CheckGLError();
1781 }
1782 
TexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)1783 void GLES2Implementation::TexSubImage2D(
1784     GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1785     GLsizei height, GLenum format, GLenum type, const void* pixels) {
1786   GPU_CLIENT_SINGLE_THREAD_CHECK();
1787   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1788       << GLES2Util::GetStringTextureTarget(target) << ", "
1789       << level << ", "
1790       << xoffset << ", " << yoffset << ", "
1791       << width << ", " << height << ", "
1792       << GLES2Util::GetStringTextureFormat(format) << ", "
1793       << GLES2Util::GetStringPixelType(type) << ", "
1794       << static_cast<const void*>(pixels) << ")");
1795 
1796   if (level < 0 || height < 0 || width < 0) {
1797     SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1798     return;
1799   }
1800   if (height == 0 || width == 0) {
1801     return;
1802   }
1803 
1804   uint32 temp_size;
1805   uint32 unpadded_row_size;
1806   uint32 padded_row_size;
1807   if (!GLES2Util::ComputeImageDataSizes(
1808         width, height, format, type, unpack_alignment_, &temp_size,
1809         &unpadded_row_size, &padded_row_size)) {
1810     SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1811     return;
1812   }
1813 
1814   // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1815   if (bound_pixel_unpack_transfer_buffer_id_) {
1816     GLuint offset = ToGLuint(pixels);
1817     BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1818         bound_pixel_unpack_transfer_buffer_id_,
1819         "glTexSubImage2D", offset, temp_size);
1820     if (buffer && buffer->shm_id() != -1) {
1821       helper_->TexSubImage2D(
1822           target, level, xoffset, yoffset, width, height, format, type,
1823           buffer->shm_id(), buffer->shm_offset() + offset, false);
1824       buffer->set_transfer_ready_token(helper_->InsertToken());
1825       CheckGLError();
1826     }
1827     return;
1828   }
1829 
1830   // compute the advance bytes per row for the src pixels
1831   uint32 src_padded_row_size;
1832   if (unpack_row_length_ > 0) {
1833     if (!GLES2Util::ComputeImagePaddedRowSize(
1834         unpack_row_length_, format, type, unpack_alignment_,
1835         &src_padded_row_size)) {
1836       SetGLError(
1837           GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1838       return;
1839     }
1840   } else {
1841     src_padded_row_size = padded_row_size;
1842   }
1843 
1844   // advance pixels pointer past the skip rows and skip pixels
1845   pixels = reinterpret_cast<const int8*>(pixels) +
1846       unpack_skip_rows_ * src_padded_row_size;
1847   if (unpack_skip_pixels_) {
1848     uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1849     pixels = reinterpret_cast<const int8*>(pixels) +
1850         unpack_skip_pixels_ * group_size;
1851   }
1852 
1853   ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1854   TexSubImage2DImpl(
1855       target, level, xoffset, yoffset, width, height, format, type,
1856       unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1857       padded_row_size);
1858   CheckGLError();
1859 }
1860 
ComputeNumRowsThatFitInBuffer(GLsizeiptr padded_row_size,GLsizeiptr unpadded_row_size,unsigned int size)1861 static GLint ComputeNumRowsThatFitInBuffer(
1862     GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1863     unsigned int size) {
1864   DCHECK_GE(unpadded_row_size, 0);
1865   if (padded_row_size == 0) {
1866     return 1;
1867   }
1868   GLint num_rows = size / padded_row_size;
1869   return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1870 }
1871 
TexSubImage2DImpl(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,uint32 unpadded_row_size,const void * pixels,uint32 pixels_padded_row_size,GLboolean internal,ScopedTransferBufferPtr * buffer,uint32 buffer_padded_row_size)1872 void GLES2Implementation::TexSubImage2DImpl(
1873     GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1874     GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1875     const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1876     ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1877   DCHECK(buffer);
1878   DCHECK_GE(level, 0);
1879   DCHECK_GT(height, 0);
1880   DCHECK_GT(width, 0);
1881 
1882   const int8* source = reinterpret_cast<const int8*>(pixels);
1883   GLint original_yoffset = yoffset;
1884   // Transfer by rows.
1885   while (height) {
1886     unsigned int desired_size =
1887         buffer_padded_row_size * (height - 1) + unpadded_row_size;
1888     if (!buffer->valid() || buffer->size() == 0) {
1889       buffer->Reset(desired_size);
1890       if (!buffer->valid()) {
1891         return;
1892       }
1893     }
1894 
1895     GLint num_rows = ComputeNumRowsThatFitInBuffer(
1896         buffer_padded_row_size, unpadded_row_size, buffer->size());
1897     num_rows = std::min(num_rows, height);
1898     CopyRectToBuffer(
1899         source, num_rows, unpadded_row_size, pixels_padded_row_size,
1900         unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1901     GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1902     helper_->TexSubImage2D(
1903         target, level, xoffset, y, width, num_rows, format, type,
1904         buffer->shm_id(), buffer->offset(), internal);
1905     buffer->Release();
1906     yoffset += num_rows;
1907     source += num_rows * pixels_padded_row_size;
1908     height -= num_rows;
1909   }
1910 }
1911 
GetActiveAttribHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)1912 bool GLES2Implementation::GetActiveAttribHelper(
1913     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1914     GLenum* type, char* name) {
1915   // Clear the bucket so if the command fails nothing will be in it.
1916   helper_->SetBucketSize(kResultBucketId, 0);
1917   typedef cmds::GetActiveAttrib::Result Result;
1918   Result* result = GetResultAs<Result*>();
1919   if (!result) {
1920     return false;
1921   }
1922   // Set as failed so if the command fails we'll recover.
1923   result->success = false;
1924   helper_->GetActiveAttrib(program, index, kResultBucketId,
1925                            GetResultShmId(), GetResultShmOffset());
1926   WaitForCmd();
1927   if (result->success) {
1928     if (size) {
1929       *size = result->size;
1930     }
1931     if (type) {
1932       *type = result->type;
1933     }
1934     if (length || name) {
1935       std::vector<int8> str;
1936       GetBucketContents(kResultBucketId, &str);
1937       GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1938                                   std::max(static_cast<size_t>(0),
1939                                            str.size() - 1));
1940       if (length) {
1941         *length = max_size;
1942       }
1943       if (name && bufsize > 0) {
1944         memcpy(name, &str[0], max_size);
1945         name[max_size] = '\0';
1946       }
1947     }
1948   }
1949   return result->success != 0;
1950 }
1951 
GetActiveAttrib(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)1952 void GLES2Implementation::GetActiveAttrib(
1953     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1954     GLenum* type, char* name) {
1955   GPU_CLIENT_SINGLE_THREAD_CHECK();
1956   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1957       << program << ", " << index << ", " << bufsize << ", "
1958       << static_cast<const void*>(length) << ", "
1959       << static_cast<const void*>(size) << ", "
1960       << static_cast<const void*>(type) << ", "
1961       << static_cast<const void*>(name) << ", ");
1962   if (bufsize < 0) {
1963     SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1964     return;
1965   }
1966   TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1967   bool success = share_group_->program_info_manager()->GetActiveAttrib(
1968         this, program, index, bufsize, length, size, type, name);
1969   if (success) {
1970     if (size) {
1971       GPU_CLIENT_LOG("  size: " << *size);
1972     }
1973     if (type) {
1974       GPU_CLIENT_LOG("  type: " << GLES2Util::GetStringEnum(*type));
1975     }
1976     if (name) {
1977       GPU_CLIENT_LOG("  name: " << name);
1978     }
1979   }
1980   CheckGLError();
1981 }
1982 
GetActiveUniformHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)1983 bool GLES2Implementation::GetActiveUniformHelper(
1984     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1985     GLenum* type, char* name) {
1986   // Clear the bucket so if the command fails nothing will be in it.
1987   helper_->SetBucketSize(kResultBucketId, 0);
1988   typedef cmds::GetActiveUniform::Result Result;
1989   Result* result = GetResultAs<Result*>();
1990   if (!result) {
1991     return false;
1992   }
1993   // Set as failed so if the command fails we'll recover.
1994   result->success = false;
1995   helper_->GetActiveUniform(program, index, kResultBucketId,
1996                             GetResultShmId(), GetResultShmOffset());
1997   WaitForCmd();
1998   if (result->success) {
1999     if (size) {
2000       *size = result->size;
2001     }
2002     if (type) {
2003       *type = result->type;
2004     }
2005     if (length || name) {
2006       std::vector<int8> str;
2007       GetBucketContents(kResultBucketId, &str);
2008       GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2009                                   std::max(static_cast<size_t>(0),
2010                                            str.size() - 1));
2011       if (length) {
2012         *length = max_size;
2013       }
2014       if (name && bufsize > 0) {
2015         memcpy(name, &str[0], max_size);
2016         name[max_size] = '\0';
2017       }
2018     }
2019   }
2020   return result->success != 0;
2021 }
2022 
GetActiveUniform(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)2023 void GLES2Implementation::GetActiveUniform(
2024     GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2025     GLenum* type, char* name) {
2026   GPU_CLIENT_SINGLE_THREAD_CHECK();
2027   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2028       << program << ", " << index << ", " << bufsize << ", "
2029       << static_cast<const void*>(length) << ", "
2030       << static_cast<const void*>(size) << ", "
2031       << static_cast<const void*>(type) << ", "
2032       << static_cast<const void*>(name) << ", ");
2033   if (bufsize < 0) {
2034     SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2035     return;
2036   }
2037   TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2038   bool success = share_group_->program_info_manager()->GetActiveUniform(
2039       this, program, index, bufsize, length, size, type, name);
2040   if (success) {
2041     if (size) {
2042       GPU_CLIENT_LOG("  size: " << *size);
2043     }
2044     if (type) {
2045       GPU_CLIENT_LOG("  type: " << GLES2Util::GetStringEnum(*type));
2046     }
2047     if (name) {
2048       GPU_CLIENT_LOG("  name: " << name);
2049     }
2050   }
2051   CheckGLError();
2052 }
2053 
GetAttachedShaders(GLuint program,GLsizei maxcount,GLsizei * count,GLuint * shaders)2054 void GLES2Implementation::GetAttachedShaders(
2055     GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2056   GPU_CLIENT_SINGLE_THREAD_CHECK();
2057   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2058       << program << ", " << maxcount << ", "
2059       << static_cast<const void*>(count) << ", "
2060       << static_cast<const void*>(shaders) << ", ");
2061   if (maxcount < 0) {
2062     SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2063     return;
2064   }
2065   TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2066   typedef cmds::GetAttachedShaders::Result Result;
2067   uint32 size = Result::ComputeSize(maxcount);
2068   Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2069   if (!result) {
2070     return;
2071   }
2072   result->SetNumResults(0);
2073   helper_->GetAttachedShaders(
2074     program,
2075     transfer_buffer_->GetShmId(),
2076     transfer_buffer_->GetOffset(result),
2077     size);
2078   int32 token = helper_->InsertToken();
2079   WaitForCmd();
2080   if (count) {
2081     *count = result->GetNumResults();
2082   }
2083   result->CopyResult(shaders);
2084   GPU_CLIENT_LOG_CODE_BLOCK({
2085     for (int32 i = 0; i < result->GetNumResults(); ++i) {
2086       GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
2087     }
2088   });
2089   transfer_buffer_->FreePendingToken(result, token);
2090   CheckGLError();
2091 }
2092 
GetShaderPrecisionFormat(GLenum shadertype,GLenum precisiontype,GLint * range,GLint * precision)2093 void GLES2Implementation::GetShaderPrecisionFormat(
2094     GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2095   GPU_CLIENT_SINGLE_THREAD_CHECK();
2096   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2097       << GLES2Util::GetStringShaderType(shadertype) << ", "
2098       << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2099       << static_cast<const void*>(range) << ", "
2100       << static_cast<const void*>(precision) << ", ");
2101   TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2102   typedef cmds::GetShaderPrecisionFormat::Result Result;
2103   Result* result = GetResultAs<Result*>();
2104   if (!result) {
2105     return;
2106   }
2107 
2108   GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2109   GLStaticState::ShaderPrecisionMap::iterator i =
2110       static_state_.shader_precisions.find(key);
2111   if (i != static_state_.shader_precisions.end()) {
2112     *result = i->second;
2113   } else {
2114     result->success = false;
2115     helper_->GetShaderPrecisionFormat(
2116         shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2117     WaitForCmd();
2118     if (result->success)
2119       static_state_.shader_precisions[key] = *result;
2120   }
2121 
2122   if (result->success) {
2123     if (range) {
2124       range[0] = result->min_range;
2125       range[1] = result->max_range;
2126       GPU_CLIENT_LOG("  min_range: " << range[0]);
2127       GPU_CLIENT_LOG("  min_range: " << range[1]);
2128     }
2129     if (precision) {
2130       precision[0] = result->precision;
2131       GPU_CLIENT_LOG("  min_range: " << precision[0]);
2132     }
2133   }
2134   CheckGLError();
2135 }
2136 
GetStringHelper(GLenum name)2137 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2138   const char* result = NULL;
2139   // Clears the bucket so if the command fails nothing will be in it.
2140   helper_->SetBucketSize(kResultBucketId, 0);
2141   helper_->GetString(name, kResultBucketId);
2142   std::string str;
2143   if (GetBucketAsString(kResultBucketId, &str)) {
2144     // Adds extensions implemented on client side only.
2145     switch (name) {
2146       case GL_EXTENSIONS:
2147         str += std::string(str.empty() ? "" : " ") +
2148             "GL_CHROMIUM_flipy "
2149             "GL_EXT_unpack_subimage";
2150         if (capabilities_.map_image) {
2151           // The first space character is intentional.
2152           str += " GL_CHROMIUM_map_image";
2153         }
2154         break;
2155       default:
2156         break;
2157     }
2158 
2159     // Because of WebGL the extensions can change. We have to cache each unique
2160     // result since we don't know when the client will stop referring to a
2161     // previous one it queries.
2162     GLStringMap::iterator it = gl_strings_.find(name);
2163     if (it == gl_strings_.end()) {
2164       std::set<std::string> strings;
2165       std::pair<GLStringMap::iterator, bool> insert_result =
2166           gl_strings_.insert(std::make_pair(name, strings));
2167       DCHECK(insert_result.second);
2168       it = insert_result.first;
2169     }
2170     std::set<std::string>& string_set = it->second;
2171     std::set<std::string>::const_iterator sit = string_set.find(str);
2172     if (sit != string_set.end()) {
2173       result = sit->c_str();
2174     } else {
2175       std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2176           string_set.insert(str);
2177       DCHECK(insert_result.second);
2178       result = insert_result.first->c_str();
2179     }
2180   }
2181   return reinterpret_cast<const GLubyte*>(result);
2182 }
2183 
GetString(GLenum name)2184 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2185   GPU_CLIENT_SINGLE_THREAD_CHECK();
2186   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2187       << GLES2Util::GetStringStringType(name) << ")");
2188   TRACE_EVENT0("gpu", "GLES2::GetString");
2189   const GLubyte* result = GetStringHelper(name);
2190   GPU_CLIENT_LOG("  returned " << reinterpret_cast<const char*>(result));
2191   CheckGLError();
2192   return result;
2193 }
2194 
GetUniformfv(GLuint program,GLint location,GLfloat * params)2195 void GLES2Implementation::GetUniformfv(
2196     GLuint program, GLint location, GLfloat* params) {
2197   GPU_CLIENT_SINGLE_THREAD_CHECK();
2198   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2199       << program << ", " << location << ", "
2200       << static_cast<const void*>(params) << ")");
2201   TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2202   typedef cmds::GetUniformfv::Result Result;
2203   Result* result = GetResultAs<Result*>();
2204   if (!result) {
2205     return;
2206   }
2207   result->SetNumResults(0);
2208   helper_->GetUniformfv(
2209       program, location, GetResultShmId(), GetResultShmOffset());
2210   WaitForCmd();
2211   result->CopyResult(params);
2212   GPU_CLIENT_LOG_CODE_BLOCK({
2213     for (int32 i = 0; i < result->GetNumResults(); ++i) {
2214       GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
2215     }
2216   });
2217   CheckGLError();
2218 }
2219 
GetUniformiv(GLuint program,GLint location,GLint * params)2220 void GLES2Implementation::GetUniformiv(
2221     GLuint program, GLint location, GLint* params) {
2222   GPU_CLIENT_SINGLE_THREAD_CHECK();
2223   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2224       << program << ", " << location << ", "
2225       << static_cast<const void*>(params) << ")");
2226   TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2227   typedef cmds::GetUniformiv::Result Result;
2228   Result* result = GetResultAs<Result*>();
2229   if (!result) {
2230     return;
2231   }
2232   result->SetNumResults(0);
2233   helper_->GetUniformiv(
2234       program, location, GetResultShmId(), GetResultShmOffset());
2235   WaitForCmd();
2236   GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2237   GPU_CLIENT_LOG_CODE_BLOCK({
2238     for (int32 i = 0; i < result->GetNumResults(); ++i) {
2239       GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
2240     }
2241   });
2242   CheckGLError();
2243 }
2244 
ReadPixels(GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,void * pixels)2245 void GLES2Implementation::ReadPixels(
2246     GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2247     GLenum type, void* pixels) {
2248   GPU_CLIENT_SINGLE_THREAD_CHECK();
2249   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2250       << xoffset << ", " << yoffset << ", "
2251       << width << ", " << height << ", "
2252       << GLES2Util::GetStringReadPixelFormat(format) << ", "
2253       << GLES2Util::GetStringPixelType(type) << ", "
2254       << static_cast<const void*>(pixels) << ")");
2255   if (width < 0 || height < 0) {
2256     SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2257     return;
2258   }
2259   if (width == 0 || height == 0) {
2260     return;
2261   }
2262 
2263   // glReadPixel pads the size of each row of pixels by an amount specified by
2264   // glPixelStorei. So, we have to take that into account both in the fact that
2265   // the pixels returned from the ReadPixel command will include that padding
2266   // and that when we copy the results to the user's buffer we need to not
2267   // write those padding bytes but leave them as they are.
2268 
2269   TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2270   typedef cmds::ReadPixels::Result Result;
2271 
2272   int8* dest = reinterpret_cast<int8*>(pixels);
2273   uint32 temp_size;
2274   uint32 unpadded_row_size;
2275   uint32 padded_row_size;
2276   if (!GLES2Util::ComputeImageDataSizes(
2277       width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2278       &padded_row_size)) {
2279     SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2280     return;
2281   }
2282 
2283   if (bound_pixel_pack_transfer_buffer_id_) {
2284     GLuint offset = ToGLuint(pixels);
2285     BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2286         bound_pixel_pack_transfer_buffer_id_,
2287         "glReadPixels", offset, padded_row_size * height);
2288     if (buffer && buffer->shm_id() != -1) {
2289       helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2290                           buffer->shm_id(), buffer->shm_offset(),
2291                           0, 0, true);
2292       CheckGLError();
2293     }
2294     return;
2295   }
2296 
2297   if (!pixels) {
2298     SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2299     return;
2300   }
2301 
2302   // Transfer by rows.
2303   // The max rows we can transfer.
2304   while (height) {
2305     GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2306     ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2307     if (!buffer.valid()) {
2308       return;
2309     }
2310     GLint num_rows = ComputeNumRowsThatFitInBuffer(
2311         padded_row_size, unpadded_row_size, buffer.size());
2312     num_rows = std::min(num_rows, height);
2313     // NOTE: We must look up the address of the result area AFTER allocation
2314     // of the transfer buffer since the transfer buffer may be reallocated.
2315     Result* result = GetResultAs<Result*>();
2316     if (!result) {
2317       return;
2318     }
2319     *result = 0;  // mark as failed.
2320     helper_->ReadPixels(
2321         xoffset, yoffset, width, num_rows, format, type,
2322         buffer.shm_id(), buffer.offset(),
2323         GetResultShmId(), GetResultShmOffset(),
2324         false);
2325     WaitForCmd();
2326     if (*result != 0) {
2327       // when doing a y-flip we have to iterate through top-to-bottom chunks
2328       // of the dst. The service side handles reversing the rows within a
2329       // chunk.
2330       int8* rows_dst;
2331       if (pack_reverse_row_order_) {
2332           rows_dst = dest + (height - num_rows) * padded_row_size;
2333       } else {
2334           rows_dst = dest;
2335       }
2336       // We have to copy 1 row at a time to avoid writing pad bytes.
2337       const int8* src = static_cast<const int8*>(buffer.address());
2338       for (GLint yy = 0; yy < num_rows; ++yy) {
2339         memcpy(rows_dst, src, unpadded_row_size);
2340         rows_dst += padded_row_size;
2341         src += padded_row_size;
2342       }
2343       if (!pack_reverse_row_order_) {
2344         dest = rows_dst;
2345       }
2346     }
2347     // If it was not marked as successful exit.
2348     if (*result == 0) {
2349       return;
2350     }
2351     yoffset += num_rows;
2352     height -= num_rows;
2353   }
2354   CheckGLError();
2355 }
2356 
ActiveTexture(GLenum texture)2357 void GLES2Implementation::ActiveTexture(GLenum texture) {
2358   GPU_CLIENT_SINGLE_THREAD_CHECK();
2359   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2360       << GLES2Util::GetStringEnum(texture) << ")");
2361   GLuint texture_index = texture - GL_TEXTURE0;
2362   if (texture_index >= static_cast<GLuint>(
2363       static_state_.int_state.max_combined_texture_image_units)) {
2364     SetGLErrorInvalidEnum(
2365         "glActiveTexture", texture, "texture");
2366     return;
2367   }
2368 
2369   active_texture_unit_ = texture_index;
2370   helper_->ActiveTexture(texture);
2371   CheckGLError();
2372 }
2373 
GenBuffersHelper(GLsizei,const GLuint *)2374 void GLES2Implementation::GenBuffersHelper(
2375     GLsizei /* n */, const GLuint* /* buffers */) {
2376 }
2377 
GenFramebuffersHelper(GLsizei,const GLuint *)2378 void GLES2Implementation::GenFramebuffersHelper(
2379     GLsizei /* n */, const GLuint* /* framebuffers */) {
2380 }
2381 
GenRenderbuffersHelper(GLsizei,const GLuint *)2382 void GLES2Implementation::GenRenderbuffersHelper(
2383     GLsizei /* n */, const GLuint* /* renderbuffers */) {
2384 }
2385 
GenTexturesHelper(GLsizei,const GLuint *)2386 void GLES2Implementation::GenTexturesHelper(
2387     GLsizei /* n */, const GLuint* /* textures */) {
2388 }
2389 
GenVertexArraysOESHelper(GLsizei n,const GLuint * arrays)2390 void GLES2Implementation::GenVertexArraysOESHelper(
2391     GLsizei n, const GLuint* arrays) {
2392   vertex_array_object_manager_->GenVertexArrays(n, arrays);
2393 }
2394 
GenQueriesEXTHelper(GLsizei,const GLuint *)2395 void GLES2Implementation::GenQueriesEXTHelper(
2396     GLsizei /* n */, const GLuint* /* queries */) {
2397 }
2398 
2399 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2400 // generates a new resource. On newer versions of OpenGL they don't. The code
2401 // related to binding below will need to change if we switch to the new OpenGL
2402 // model. Specifically it assumes a bind will succeed which is always true in
2403 // the old model but possibly not true in the new model if another context has
2404 // deleted the resource.
2405 
BindBufferHelper(GLenum target,GLuint buffer)2406 bool GLES2Implementation::BindBufferHelper(
2407     GLenum target, GLuint buffer) {
2408   // TODO(gman): See note #1 above.
2409   bool changed = false;
2410   switch (target) {
2411     case GL_ARRAY_BUFFER:
2412       if (bound_array_buffer_id_ != buffer) {
2413         bound_array_buffer_id_ = buffer;
2414         changed = true;
2415       }
2416       break;
2417     case GL_ELEMENT_ARRAY_BUFFER:
2418       changed = vertex_array_object_manager_->BindElementArray(buffer);
2419       break;
2420     case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2421       bound_pixel_pack_transfer_buffer_id_ = buffer;
2422       break;
2423     case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2424       bound_pixel_unpack_transfer_buffer_id_ = buffer;
2425       break;
2426     default:
2427       changed = true;
2428       break;
2429   }
2430   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2431   // used even though it's marked it as used here.
2432   GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2433   return changed;
2434 }
2435 
BindFramebufferHelper(GLenum target,GLuint framebuffer)2436 bool GLES2Implementation::BindFramebufferHelper(
2437     GLenum target, GLuint framebuffer) {
2438   // TODO(gman): See note #1 above.
2439   bool changed = false;
2440   switch (target) {
2441     case GL_FRAMEBUFFER:
2442       if (bound_framebuffer_ != framebuffer ||
2443           bound_read_framebuffer_ != framebuffer) {
2444         bound_framebuffer_ = framebuffer;
2445         bound_read_framebuffer_ = framebuffer;
2446         changed = true;
2447       }
2448       break;
2449     case GL_READ_FRAMEBUFFER:
2450       if (!IsChromiumFramebufferMultisampleAvailable()) {
2451         SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2452         return false;
2453       }
2454       if (bound_read_framebuffer_ != framebuffer) {
2455         bound_read_framebuffer_ = framebuffer;
2456         changed = true;
2457       }
2458       break;
2459     case GL_DRAW_FRAMEBUFFER:
2460       if (!IsChromiumFramebufferMultisampleAvailable()) {
2461         SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2462         return false;
2463       }
2464       if (bound_framebuffer_ != framebuffer) {
2465         bound_framebuffer_ = framebuffer;
2466         changed = true;
2467       }
2468       break;
2469     default:
2470       SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2471       return false;
2472   }
2473   GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2474   return changed;
2475 }
2476 
BindRenderbufferHelper(GLenum target,GLuint renderbuffer)2477 bool GLES2Implementation::BindRenderbufferHelper(
2478     GLenum target, GLuint renderbuffer) {
2479   // TODO(gman): See note #1 above.
2480   bool changed = false;
2481   switch (target) {
2482     case GL_RENDERBUFFER:
2483       if (bound_renderbuffer_ != renderbuffer) {
2484         bound_renderbuffer_ = renderbuffer;
2485         changed = true;
2486       }
2487       break;
2488     default:
2489       changed = true;
2490       break;
2491   }
2492   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2493   // used even though it's marked it as used here.
2494   GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2495   return changed;
2496 }
2497 
BindTextureHelper(GLenum target,GLuint texture)2498 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2499   // TODO(gman): See note #1 above.
2500   // TODO(gman): Change this to false once we figure out why it's failing
2501   //     on daisy.
2502   bool changed = true;
2503   TextureUnit& unit = texture_units_[active_texture_unit_];
2504   switch (target) {
2505     case GL_TEXTURE_2D:
2506       if (unit.bound_texture_2d != texture) {
2507         unit.bound_texture_2d = texture;
2508         changed = true;
2509       }
2510       break;
2511     case GL_TEXTURE_CUBE_MAP:
2512       if (unit.bound_texture_cube_map != texture) {
2513         unit.bound_texture_cube_map = texture;
2514         changed = true;
2515       }
2516       break;
2517     case GL_TEXTURE_EXTERNAL_OES:
2518       if (unit.bound_texture_external_oes != texture) {
2519         unit.bound_texture_external_oes = texture;
2520         changed = true;
2521       }
2522       break;
2523     default:
2524       changed = true;
2525       break;
2526   }
2527   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2528   // used. even though it's marked it as used here.
2529   GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2530   return changed;
2531 }
2532 
BindVertexArrayHelper(GLuint array)2533 bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
2534   // TODO(gman): See note #1 above.
2535   bool changed = false;
2536   if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2537     SetGLError(
2538         GL_INVALID_OPERATION, "glBindVertexArrayOES",
2539         "id was not generated with glGenVertexArrayOES");
2540   }
2541   // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2542   // because unlike other resources VertexArrayObject ids must
2543   // be generated by GenVertexArrays. A random id to Bind will not
2544   // generate a new object.
2545   return changed;
2546 }
2547 
IsBufferReservedId(GLuint id)2548 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2549   return vertex_array_object_manager_->IsReservedId(id);
2550 }
2551 
DeleteBuffersHelper(GLsizei n,const GLuint * buffers)2552 void GLES2Implementation::DeleteBuffersHelper(
2553     GLsizei n, const GLuint* buffers) {
2554   if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2555       this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2556     SetGLError(
2557         GL_INVALID_VALUE,
2558         "glDeleteBuffers", "id not created by this context.");
2559     return;
2560   }
2561   for (GLsizei ii = 0; ii < n; ++ii) {
2562     if (buffers[ii] == bound_array_buffer_id_) {
2563       bound_array_buffer_id_ = 0;
2564     }
2565     vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2566     BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2567     if (buffer) {
2568       // Free buffer memory, pending the passage of a token.
2569       buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2570       // Remove buffer.
2571       buffer_tracker_->RemoveBuffer(buffers[ii]);
2572     }
2573     if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2574       bound_pixel_unpack_transfer_buffer_id_ = 0;
2575     }
2576   }
2577 }
2578 
DeleteBuffersStub(GLsizei n,const GLuint * buffers)2579 void GLES2Implementation::DeleteBuffersStub(
2580     GLsizei n, const GLuint* buffers) {
2581   helper_->DeleteBuffersImmediate(n, buffers);
2582 }
2583 
2584 
DeleteFramebuffersHelper(GLsizei n,const GLuint * framebuffers)2585 void GLES2Implementation::DeleteFramebuffersHelper(
2586     GLsizei n, const GLuint* framebuffers) {
2587   if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2588       this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2589     SetGLError(
2590         GL_INVALID_VALUE,
2591         "glDeleteFramebuffers", "id not created by this context.");
2592     return;
2593   }
2594   for (GLsizei ii = 0; ii < n; ++ii) {
2595     if (framebuffers[ii] == bound_framebuffer_) {
2596       bound_framebuffer_ = 0;
2597     }
2598     if (framebuffers[ii] == bound_read_framebuffer_) {
2599       bound_read_framebuffer_ = 0;
2600     }
2601   }
2602 }
2603 
DeleteFramebuffersStub(GLsizei n,const GLuint * framebuffers)2604 void GLES2Implementation::DeleteFramebuffersStub(
2605     GLsizei n, const GLuint* framebuffers) {
2606   helper_->DeleteFramebuffersImmediate(n, framebuffers);
2607 }
2608 
DeleteRenderbuffersHelper(GLsizei n,const GLuint * renderbuffers)2609 void GLES2Implementation::DeleteRenderbuffersHelper(
2610     GLsizei n, const GLuint* renderbuffers) {
2611   if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2612       this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2613     SetGLError(
2614         GL_INVALID_VALUE,
2615         "glDeleteRenderbuffers", "id not created by this context.");
2616     return;
2617   }
2618   for (GLsizei ii = 0; ii < n; ++ii) {
2619     if (renderbuffers[ii] == bound_renderbuffer_) {
2620       bound_renderbuffer_ = 0;
2621     }
2622   }
2623 }
2624 
DeleteRenderbuffersStub(GLsizei n,const GLuint * renderbuffers)2625 void GLES2Implementation::DeleteRenderbuffersStub(
2626     GLsizei n, const GLuint* renderbuffers) {
2627   helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2628 }
2629 
DeleteTexturesHelper(GLsizei n,const GLuint * textures)2630 void GLES2Implementation::DeleteTexturesHelper(
2631     GLsizei n, const GLuint* textures) {
2632   if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2633       this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2634     SetGLError(
2635         GL_INVALID_VALUE,
2636         "glDeleteTextures", "id not created by this context.");
2637     return;
2638   }
2639   for (GLsizei ii = 0; ii < n; ++ii) {
2640     for (GLint tt = 0;
2641          tt < static_state_.int_state.max_combined_texture_image_units;
2642          ++tt) {
2643       TextureUnit& unit = texture_units_[tt];
2644       if (textures[ii] == unit.bound_texture_2d) {
2645         unit.bound_texture_2d = 0;
2646       }
2647       if (textures[ii] == unit.bound_texture_cube_map) {
2648         unit.bound_texture_cube_map = 0;
2649       }
2650       if (textures[ii] == unit.bound_texture_external_oes) {
2651         unit.bound_texture_external_oes = 0;
2652       }
2653     }
2654   }
2655 }
2656 
DeleteVertexArraysOESHelper(GLsizei n,const GLuint * arrays)2657 void GLES2Implementation::DeleteVertexArraysOESHelper(
2658     GLsizei n, const GLuint* arrays) {
2659   vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2660   if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2661       this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2662     SetGLError(
2663         GL_INVALID_VALUE,
2664         "glDeleteVertexArraysOES", "id not created by this context.");
2665     return;
2666   }
2667 }
2668 
DeleteVertexArraysOESStub(GLsizei n,const GLuint * arrays)2669 void GLES2Implementation::DeleteVertexArraysOESStub(
2670     GLsizei n, const GLuint* arrays) {
2671   helper_->DeleteVertexArraysOESImmediate(n, arrays);
2672 }
2673 
DeleteTexturesStub(GLsizei n,const GLuint * textures)2674 void GLES2Implementation::DeleteTexturesStub(
2675     GLsizei n, const GLuint* textures) {
2676   helper_->DeleteTexturesImmediate(n, textures);
2677 }
2678 
DisableVertexAttribArray(GLuint index)2679 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2680   GPU_CLIENT_SINGLE_THREAD_CHECK();
2681   GPU_CLIENT_LOG(
2682       "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2683   vertex_array_object_manager_->SetAttribEnable(index, false);
2684   helper_->DisableVertexAttribArray(index);
2685   CheckGLError();
2686 }
2687 
EnableVertexAttribArray(GLuint index)2688 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2689   GPU_CLIENT_SINGLE_THREAD_CHECK();
2690   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2691       << index << ")");
2692   vertex_array_object_manager_->SetAttribEnable(index, true);
2693   helper_->EnableVertexAttribArray(index);
2694   CheckGLError();
2695 }
2696 
DrawArrays(GLenum mode,GLint first,GLsizei count)2697 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2698   GPU_CLIENT_SINGLE_THREAD_CHECK();
2699   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2700       << GLES2Util::GetStringDrawMode(mode) << ", "
2701       << first << ", " << count << ")");
2702   if (count < 0) {
2703     SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2704     return;
2705   }
2706   bool simulated = false;
2707   if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2708       "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2709     return;
2710   }
2711   helper_->DrawArrays(mode, first, count);
2712   RestoreArrayBuffer(simulated);
2713   CheckGLError();
2714 }
2715 
GetVertexAttribfv(GLuint index,GLenum pname,GLfloat * params)2716 void GLES2Implementation::GetVertexAttribfv(
2717     GLuint index, GLenum pname, GLfloat* params) {
2718   GPU_CLIENT_SINGLE_THREAD_CHECK();
2719   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2720       << index << ", "
2721       << GLES2Util::GetStringVertexAttribute(pname) << ", "
2722       << static_cast<const void*>(params) << ")");
2723   uint32 value = 0;
2724   if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2725     *params = static_cast<float>(value);
2726     return;
2727   }
2728   TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2729   typedef cmds::GetVertexAttribfv::Result Result;
2730   Result* result = GetResultAs<Result*>();
2731   if (!result) {
2732     return;
2733   }
2734   result->SetNumResults(0);
2735   helper_->GetVertexAttribfv(
2736       index, pname, GetResultShmId(), GetResultShmOffset());
2737   WaitForCmd();
2738   result->CopyResult(params);
2739   GPU_CLIENT_LOG_CODE_BLOCK({
2740     for (int32 i = 0; i < result->GetNumResults(); ++i) {
2741       GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
2742     }
2743   });
2744   CheckGLError();
2745 }
2746 
GetVertexAttribiv(GLuint index,GLenum pname,GLint * params)2747 void GLES2Implementation::GetVertexAttribiv(
2748     GLuint index, GLenum pname, GLint* params) {
2749   GPU_CLIENT_SINGLE_THREAD_CHECK();
2750   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2751       << index << ", "
2752       << GLES2Util::GetStringVertexAttribute(pname) << ", "
2753       << static_cast<const void*>(params) << ")");
2754   uint32 value = 0;
2755   if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2756     *params = value;
2757     return;
2758   }
2759   TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2760   typedef cmds::GetVertexAttribiv::Result Result;
2761   Result* result = GetResultAs<Result*>();
2762   if (!result) {
2763     return;
2764   }
2765   result->SetNumResults(0);
2766   helper_->GetVertexAttribiv(
2767       index, pname, GetResultShmId(), GetResultShmOffset());
2768   WaitForCmd();
2769   result->CopyResult(params);
2770   GPU_CLIENT_LOG_CODE_BLOCK({
2771     for (int32 i = 0; i < result->GetNumResults(); ++i) {
2772       GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
2773     }
2774   });
2775   CheckGLError();
2776 }
2777 
Swap()2778 void GLES2Implementation::Swap() {
2779   SwapBuffers();
2780   gpu_control_->Echo(
2781       base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2782                  weak_ptr_factory_.GetWeakPtr()));
2783 }
2784 
PartialSwapBuffers(gfx::Rect sub_buffer)2785 void GLES2Implementation::PartialSwapBuffers(gfx::Rect sub_buffer) {
2786   PostSubBufferCHROMIUM(sub_buffer.x(),
2787                         sub_buffer.y(),
2788                         sub_buffer.width(),
2789                         sub_buffer.height());
2790   gpu_control_->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2791                                 weak_ptr_factory_.GetWeakPtr()));
2792 }
2793 
SetSwapBuffersCompleteCallback(const base::Closure & swap_buffers_complete_callback)2794 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2795       const base::Closure& swap_buffers_complete_callback) {
2796   swap_buffers_complete_callback_ = swap_buffers_complete_callback;
2797 }
2798 
OnSwapBuffersComplete()2799 void GLES2Implementation::OnSwapBuffersComplete() {
2800   if (!swap_buffers_complete_callback_.is_null())
2801     swap_buffers_complete_callback_.Run();
2802 }
2803 
EnableFeatureCHROMIUM(const char * feature)2804 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2805     const char* feature) {
2806   GPU_CLIENT_SINGLE_THREAD_CHECK();
2807   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2808                  << feature << ")");
2809   TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2810   typedef cmds::EnableFeatureCHROMIUM::Result Result;
2811   Result* result = GetResultAs<Result*>();
2812   if (!result) {
2813     return false;
2814   }
2815   *result = 0;
2816   SetBucketAsCString(kResultBucketId, feature);
2817   helper_->EnableFeatureCHROMIUM(
2818       kResultBucketId, GetResultShmId(), GetResultShmOffset());
2819   WaitForCmd();
2820   helper_->SetBucketSize(kResultBucketId, 0);
2821   GPU_CLIENT_LOG("   returned " << GLES2Util::GetStringBool(*result));
2822   return *result;
2823 }
2824 
MapBufferSubDataCHROMIUM(GLuint target,GLintptr offset,GLsizeiptr size,GLenum access)2825 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2826     GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2827   GPU_CLIENT_SINGLE_THREAD_CHECK();
2828   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2829       << target << ", " << offset << ", " << size << ", "
2830       << GLES2Util::GetStringEnum(access) << ")");
2831   // NOTE: target is NOT checked because the service will check it
2832   // and we don't know what targets are valid.
2833   if (access != GL_WRITE_ONLY) {
2834     SetGLErrorInvalidEnum(
2835         "glMapBufferSubDataCHROMIUM", access, "access");
2836     return NULL;
2837   }
2838   if (offset < 0 || size < 0) {
2839     SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2840     return NULL;
2841   }
2842   int32 shm_id;
2843   unsigned int shm_offset;
2844   void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2845   if (!mem) {
2846     SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2847     return NULL;
2848   }
2849 
2850   std::pair<MappedBufferMap::iterator, bool> result =
2851      mapped_buffers_.insert(std::make_pair(
2852          mem,
2853          MappedBuffer(
2854              access, shm_id, mem, shm_offset, target, offset, size)));
2855   DCHECK(result.second);
2856   GPU_CLIENT_LOG("  returned " << mem);
2857   return mem;
2858 }
2859 
UnmapBufferSubDataCHROMIUM(const void * mem)2860 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2861   GPU_CLIENT_SINGLE_THREAD_CHECK();
2862   GPU_CLIENT_LOG(
2863       "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2864   MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2865   if (it == mapped_buffers_.end()) {
2866     SetGLError(
2867         GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2868     return;
2869   }
2870   const MappedBuffer& mb = it->second;
2871   helper_->BufferSubData(
2872       mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2873   mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2874   mapped_buffers_.erase(it);
2875   CheckGLError();
2876 }
2877 
MapTexSubImage2DCHROMIUM(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,GLenum access)2878 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2879      GLenum target,
2880      GLint level,
2881      GLint xoffset,
2882      GLint yoffset,
2883      GLsizei width,
2884      GLsizei height,
2885      GLenum format,
2886      GLenum type,
2887      GLenum access) {
2888   GPU_CLIENT_SINGLE_THREAD_CHECK();
2889   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2890       << target << ", " << level << ", "
2891       << xoffset << ", " << yoffset << ", "
2892       << width << ", " << height << ", "
2893       << GLES2Util::GetStringTextureFormat(format) << ", "
2894       << GLES2Util::GetStringPixelType(type) << ", "
2895       << GLES2Util::GetStringEnum(access) << ")");
2896   if (access != GL_WRITE_ONLY) {
2897     SetGLErrorInvalidEnum(
2898         "glMapTexSubImage2DCHROMIUM", access, "access");
2899     return NULL;
2900   }
2901   // NOTE: target is NOT checked because the service will check it
2902   // and we don't know what targets are valid.
2903   if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2904     SetGLError(
2905         GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2906     return NULL;
2907   }
2908   uint32 size;
2909   if (!GLES2Util::ComputeImageDataSizes(
2910       width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2911     SetGLError(
2912         GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2913     return NULL;
2914   }
2915   int32 shm_id;
2916   unsigned int shm_offset;
2917   void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2918   if (!mem) {
2919     SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2920     return NULL;
2921   }
2922 
2923   std::pair<MappedTextureMap::iterator, bool> result =
2924      mapped_textures_.insert(std::make_pair(
2925          mem,
2926          MappedTexture(
2927              access, shm_id, mem, shm_offset,
2928              target, level, xoffset, yoffset, width, height, format, type)));
2929   DCHECK(result.second);
2930   GPU_CLIENT_LOG("  returned " << mem);
2931   return mem;
2932 }
2933 
UnmapTexSubImage2DCHROMIUM(const void * mem)2934 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2935   GPU_CLIENT_SINGLE_THREAD_CHECK();
2936   GPU_CLIENT_LOG(
2937       "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2938   MappedTextureMap::iterator it = mapped_textures_.find(mem);
2939   if (it == mapped_textures_.end()) {
2940     SetGLError(
2941         GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2942     return;
2943   }
2944   const MappedTexture& mt = it->second;
2945   helper_->TexSubImage2D(
2946       mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2947       mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2948   mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2949   mapped_textures_.erase(it);
2950   CheckGLError();
2951 }
2952 
ResizeCHROMIUM(GLuint width,GLuint height,float scale_factor)2953 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2954                                          float scale_factor) {
2955   GPU_CLIENT_SINGLE_THREAD_CHECK();
2956   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2957                  << width << ", " << height << ", " << scale_factor << ")");
2958   helper_->ResizeCHROMIUM(width, height, scale_factor);
2959   CheckGLError();
2960 }
2961 
GetRequestableExtensionsCHROMIUM()2962 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2963   GPU_CLIENT_SINGLE_THREAD_CHECK();
2964   GPU_CLIENT_LOG("[" << GetLogPrefix()
2965       << "] glGetRequestableExtensionsCHROMIUM()");
2966   TRACE_EVENT0("gpu",
2967                "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2968   const char* result = NULL;
2969   // Clear the bucket so if the command fails nothing will be in it.
2970   helper_->SetBucketSize(kResultBucketId, 0);
2971   helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2972   std::string str;
2973   if (GetBucketAsString(kResultBucketId, &str)) {
2974     // The set of requestable extensions shrinks as we enable
2975     // them. Because we don't know when the client will stop referring
2976     // to a previous one it queries (see GetString) we need to cache
2977     // the unique results.
2978     std::set<std::string>::const_iterator sit =
2979         requestable_extensions_set_.find(str);
2980     if (sit != requestable_extensions_set_.end()) {
2981       result = sit->c_str();
2982     } else {
2983       std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2984           requestable_extensions_set_.insert(str);
2985       DCHECK(insert_result.second);
2986       result = insert_result.first->c_str();
2987     }
2988   }
2989   GPU_CLIENT_LOG("  returned " << result);
2990   return reinterpret_cast<const GLchar*>(result);
2991 }
2992 
2993 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2994 // with VirtualGL contexts.
RequestExtensionCHROMIUM(const char * extension)2995 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2996   GPU_CLIENT_SINGLE_THREAD_CHECK();
2997   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2998                  << extension << ")");
2999   SetBucketAsCString(kResultBucketId, extension);
3000   helper_->RequestExtensionCHROMIUM(kResultBucketId);
3001   helper_->SetBucketSize(kResultBucketId, 0);
3002 
3003   struct ExtensionCheck {
3004     const char* extension;
3005     ExtensionStatus* status;
3006   };
3007   const ExtensionCheck checks[] = {
3008     {
3009       "GL_ANGLE_pack_reverse_row_order",
3010       &angle_pack_reverse_row_order_status_,
3011     },
3012     {
3013       "GL_CHROMIUM_framebuffer_multisample",
3014        &chromium_framebuffer_multisample_,
3015     },
3016   };
3017   const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3018   for (size_t ii = 0; ii < kNumChecks; ++ii) {
3019     const ExtensionCheck& check = checks[ii];
3020     if (*check.status == kUnavailableExtensionStatus &&
3021         !strcmp(extension, check.extension)) {
3022       *check.status = kUnknownExtensionStatus;
3023     }
3024   }
3025 }
3026 
RateLimitOffscreenContextCHROMIUM()3027 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3028   GPU_CLIENT_SINGLE_THREAD_CHECK();
3029   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3030   // Wait if this would add too many rate limit tokens.
3031   if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3032     helper_->WaitForToken(rate_limit_tokens_.front());
3033     rate_limit_tokens_.pop();
3034   }
3035   rate_limit_tokens_.push(helper_->InsertToken());
3036 }
3037 
GetMultipleIntegervCHROMIUM(const GLenum * pnames,GLuint count,GLint * results,GLsizeiptr size)3038 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3039     const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
3040   GPU_CLIENT_SINGLE_THREAD_CHECK();
3041   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3042                  << static_cast<const void*>(pnames) << ", "
3043                  << count << ", " << results << ", "
3044                  << size << ")");
3045   GPU_CLIENT_LOG_CODE_BLOCK({
3046     for (GLuint i = 0; i < count; ++i) {
3047       GPU_CLIENT_LOG(
3048           "  " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3049     }
3050   });
3051 
3052   GetMultipleIntegervState state(pnames, count, results, size);
3053   if (!GetMultipleIntegervSetup(&state)) {
3054     return;
3055   }
3056   state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3057   if (!state.buffer) {
3058     SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3059                "Transfer buffer allocation failed.");
3060     return;
3061   }
3062   GetMultipleIntegervRequest(&state);
3063   WaitForCmd();
3064   GetMultipleIntegervOnCompleted(&state);
3065 
3066   GPU_CLIENT_LOG("  returned");
3067   GPU_CLIENT_LOG_CODE_BLOCK({
3068     for (int i = 0; i < state.num_results; ++i) {
3069       GPU_CLIENT_LOG("  " << i << ": " << (results[i]));
3070     }
3071   });
3072 
3073   // TODO(gman): We should be able to free without a token.
3074   transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3075   CheckGLError();
3076 }
3077 
GetMultipleIntegervSetup(GetMultipleIntegervState * state)3078 bool GLES2Implementation::GetMultipleIntegervSetup(
3079     GetMultipleIntegervState* state) {
3080   state->num_results = 0;
3081   for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3082     int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3083     if (!num) {
3084       SetGLErrorInvalidEnum(
3085           "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3086       return false;
3087     }
3088     state->num_results += num;
3089   }
3090   if (static_cast<size_t>(state->results_size) !=
3091       state->num_results * sizeof(GLint)) {
3092     SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3093     return false;
3094   }
3095   for (int ii = 0; ii < state->num_results; ++ii) {
3096     if (state->results[ii] != 0) {
3097       SetGLError(GL_INVALID_VALUE,
3098                  "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3099       return false;
3100     }
3101   }
3102   state->transfer_buffer_size_needed =
3103       state->pnames_count * sizeof(state->pnames[0]) +
3104       state->num_results * sizeof(state->results[0]);
3105   return true;
3106 }
3107 
GetMultipleIntegervRequest(GetMultipleIntegervState * state)3108 void GLES2Implementation::GetMultipleIntegervRequest(
3109     GetMultipleIntegervState* state) {
3110   GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3111   state->results_buffer = pnames_buffer + state->pnames_count;
3112   memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3113   memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3114   helper_->GetMultipleIntegervCHROMIUM(
3115       transfer_buffer_->GetShmId(),
3116       transfer_buffer_->GetOffset(pnames_buffer),
3117       state->pnames_count,
3118       transfer_buffer_->GetShmId(),
3119       transfer_buffer_->GetOffset(state->results_buffer),
3120       state->results_size);
3121 }
3122 
GetMultipleIntegervOnCompleted(GetMultipleIntegervState * state)3123 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3124     GetMultipleIntegervState* state) {
3125   memcpy(state->results, state->results_buffer, state->results_size);;
3126 }
3127 
GetAllShaderPrecisionFormatsSetup(GetAllShaderPrecisionFormatsState * state)3128 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3129     GetAllShaderPrecisionFormatsState* state) {
3130   state->transfer_buffer_size_needed =
3131       state->precision_params_count *
3132       sizeof(cmds::GetShaderPrecisionFormat::Result);
3133 }
3134 
GetAllShaderPrecisionFormatsRequest(GetAllShaderPrecisionFormatsState * state)3135 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3136     GetAllShaderPrecisionFormatsState* state) {
3137   typedef cmds::GetShaderPrecisionFormat::Result Result;
3138   Result* result = static_cast<Result*>(state->results_buffer);
3139 
3140   for (int i = 0; i < state->precision_params_count; i++) {
3141     result->success = false;
3142     helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3143                                       state->precision_params[i][1],
3144                                       transfer_buffer_->GetShmId(),
3145                                       transfer_buffer_->GetOffset(result));
3146     result++;
3147   }
3148 }
3149 
GetAllShaderPrecisionFormatsOnCompleted(GetAllShaderPrecisionFormatsState * state)3150 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3151     GetAllShaderPrecisionFormatsState* state) {
3152   typedef cmds::GetShaderPrecisionFormat::Result Result;
3153   Result* result = static_cast<Result*>(state->results_buffer);
3154 
3155   for (int i = 0; i < state->precision_params_count; i++) {
3156     if (result->success) {
3157       const GLStaticState::ShaderPrecisionKey key(
3158         state->precision_params[i][0], state->precision_params[i][1]);
3159       static_state_.shader_precisions[key] = *result;
3160     }
3161     result++;
3162   }
3163 }
3164 
GetProgramInfoCHROMIUMHelper(GLuint program,std::vector<int8> * result)3165 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3166     GLuint program, std::vector<int8>* result) {
3167   DCHECK(result);
3168   // Clear the bucket so if the command fails nothing will be in it.
3169   helper_->SetBucketSize(kResultBucketId, 0);
3170   helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3171   GetBucketContents(kResultBucketId, result);
3172 }
3173 
GetProgramInfoCHROMIUM(GLuint program,GLsizei bufsize,GLsizei * size,void * info)3174 void GLES2Implementation::GetProgramInfoCHROMIUM(
3175     GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3176   GPU_CLIENT_SINGLE_THREAD_CHECK();
3177   if (bufsize < 0) {
3178     SetGLError(
3179         GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3180     return;
3181   }
3182   if (size == NULL) {
3183     SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3184     return;
3185   }
3186   // Make sure they've set size to 0 else the value will be undefined on
3187   // lost context.
3188   DCHECK(*size == 0);
3189   std::vector<int8> result;
3190   GetProgramInfoCHROMIUMHelper(program, &result);
3191   if (result.empty()) {
3192     return;
3193   }
3194   *size = result.size();
3195   if (!info) {
3196     return;
3197   }
3198   if (static_cast<size_t>(bufsize) < result.size()) {
3199     SetGLError(GL_INVALID_OPERATION,
3200                "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3201     return;
3202   }
3203   memcpy(info, &result[0], result.size());
3204 }
3205 
CreateStreamTextureCHROMIUM(GLuint texture)3206 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3207   GPU_CLIENT_SINGLE_THREAD_CHECK();
3208   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3209       << texture << ")");
3210   TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3211   typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
3212   Result* result = GetResultAs<Result*>();
3213   if (!result) {
3214     return GL_ZERO;
3215   }
3216   *result = GL_ZERO;
3217 
3218   helper_->CreateStreamTextureCHROMIUM(texture,
3219                                        GetResultShmId(),
3220                                        GetResultShmOffset());
3221   WaitForCmd();
3222   GLuint result_value = *result;
3223   CheckGLError();
3224   return result_value;
3225 }
3226 
DestroyStreamTextureCHROMIUM(GLuint texture)3227 void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
3228   GPU_CLIENT_SINGLE_THREAD_CHECK();
3229   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
3230       << texture << ")");
3231   TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
3232   helper_->DestroyStreamTextureCHROMIUM(texture);
3233   CheckGLError();
3234 }
3235 
PostSubBufferCHROMIUM(GLint x,GLint y,GLint width,GLint height)3236 void GLES2Implementation::PostSubBufferCHROMIUM(
3237     GLint x, GLint y, GLint width, GLint height) {
3238   GPU_CLIENT_SINGLE_THREAD_CHECK();
3239   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3240       << x << ", " << y << ", " << width << ", " << height << ")");
3241   TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3242                "width", width, "height", height);
3243 
3244   // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3245   swap_buffers_tokens_.push(helper_->InsertToken());
3246   helper_->PostSubBufferCHROMIUM(x, y, width, height);
3247   helper_->CommandBufferHelper::Flush();
3248   if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3249     helper_->WaitForToken(swap_buffers_tokens_.front());
3250     swap_buffers_tokens_.pop();
3251   }
3252 }
3253 
DeleteQueriesEXTHelper(GLsizei n,const GLuint * queries)3254 void GLES2Implementation::DeleteQueriesEXTHelper(
3255     GLsizei n, const GLuint* queries) {
3256   // TODO(gman): Remove this as queries are not shared resources.
3257   if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3258       this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3259     SetGLError(
3260         GL_INVALID_VALUE,
3261         "glDeleteTextures", "id not created by this context.");
3262     return;
3263   }
3264 
3265   for (GLsizei ii = 0; ii < n; ++ii)
3266     query_tracker_->RemoveQuery(queries[ii]);
3267 
3268   helper_->DeleteQueriesEXTImmediate(n, queries);
3269 }
3270 
3271 // TODO(gman): Remove this. Queries are not shared resources.
DeleteQueriesStub(GLsizei,const GLuint *)3272 void GLES2Implementation::DeleteQueriesStub(
3273     GLsizei /* n */, const GLuint* /* queries */) {
3274 }
3275 
IsQueryEXT(GLuint id)3276 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3277   GPU_CLIENT_SINGLE_THREAD_CHECK();
3278   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3279 
3280   // TODO(gman): To be spec compliant IDs from other contexts sharing
3281   // resources need to return true here even though you can't share
3282   // queries across contexts?
3283   return query_tracker_->GetQuery(id) != NULL;
3284 }
3285 
BeginQueryEXT(GLenum target,GLuint id)3286 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3287   GPU_CLIENT_SINGLE_THREAD_CHECK();
3288   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3289                  << GLES2Util::GetStringQueryTarget(target)
3290                  << ", " << id << ")");
3291 
3292   // if any outstanding queries INV_OP
3293   if (current_query_) {
3294     SetGLError(
3295         GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3296     return;
3297   }
3298 
3299   // id = 0 INV_OP
3300   if (id == 0) {
3301     SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3302     return;
3303   }
3304 
3305   // TODO(gman) if id not GENned INV_OPERATION
3306 
3307   // if id does not have an object
3308   QueryTracker::Query* query = query_tracker_->GetQuery(id);
3309   if (!query) {
3310     query = query_tracker_->CreateQuery(id, target);
3311     if (!query) {
3312       MustBeContextLost();
3313       return;
3314     }
3315   } else if (query->target() != target) {
3316     SetGLError(
3317         GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3318     return;
3319   }
3320 
3321   current_query_ = query;
3322 
3323   query->Begin(this);
3324   CheckGLError();
3325 }
3326 
EndQueryEXT(GLenum target)3327 void GLES2Implementation::EndQueryEXT(GLenum target) {
3328   GPU_CLIENT_SINGLE_THREAD_CHECK();
3329   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3330                  << GLES2Util::GetStringQueryTarget(target) << ")");
3331   // Don't do anything if the context is lost.
3332   if (helper_->IsContextLost()) {
3333     return;
3334   }
3335 
3336   if (!current_query_) {
3337     SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3338     return;
3339   }
3340 
3341   if (current_query_->target() != target) {
3342     SetGLError(GL_INVALID_OPERATION,
3343                "glEndQueryEXT", "target does not match active query");
3344     return;
3345   }
3346 
3347   current_query_->End(this);
3348   current_query_ = NULL;
3349   CheckGLError();
3350 }
3351 
GetQueryivEXT(GLenum target,GLenum pname,GLint * params)3352 void GLES2Implementation::GetQueryivEXT(
3353     GLenum target, GLenum pname, GLint* params) {
3354   GPU_CLIENT_SINGLE_THREAD_CHECK();
3355   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3356                  << GLES2Util::GetStringQueryTarget(target) << ", "
3357                  << GLES2Util::GetStringQueryParameter(pname) << ", "
3358                  << static_cast<const void*>(params) << ")");
3359 
3360   if (pname != GL_CURRENT_QUERY_EXT) {
3361     SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3362     return;
3363   }
3364   *params = (current_query_ && current_query_->target() == target) ?
3365       current_query_->id() : 0;
3366   GPU_CLIENT_LOG("  " << *params);
3367   CheckGLError();
3368 }
3369 
GetQueryObjectuivEXT(GLuint id,GLenum pname,GLuint * params)3370 void GLES2Implementation::GetQueryObjectuivEXT(
3371     GLuint id, GLenum pname, GLuint* params) {
3372   GPU_CLIENT_SINGLE_THREAD_CHECK();
3373   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3374                  << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3375                  << static_cast<const void*>(params) << ")");
3376 
3377   QueryTracker::Query* query = query_tracker_->GetQuery(id);
3378   if (!query) {
3379     SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3380     return;
3381   }
3382 
3383   if (query == current_query_) {
3384     SetGLError(
3385         GL_INVALID_OPERATION,
3386         "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3387     return;
3388   }
3389 
3390   if (query->NeverUsed()) {
3391     SetGLError(
3392         GL_INVALID_OPERATION,
3393         "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3394     return;
3395   }
3396 
3397   switch (pname) {
3398     case GL_QUERY_RESULT_EXT:
3399       if (!query->CheckResultsAvailable(helper_)) {
3400         helper_->WaitForToken(query->token());
3401         if (!query->CheckResultsAvailable(helper_)) {
3402           // TODO(gman): Speed this up.
3403           WaitForCmd();
3404           CHECK(query->CheckResultsAvailable(helper_));
3405         }
3406       }
3407       *params = query->GetResult();
3408       break;
3409     case GL_QUERY_RESULT_AVAILABLE_EXT:
3410       *params = query->CheckResultsAvailable(helper_);
3411       break;
3412     default:
3413       SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3414       break;
3415   }
3416   GPU_CLIENT_LOG("  " << *params);
3417   CheckGLError();
3418 }
3419 
DrawArraysInstancedANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount)3420 void GLES2Implementation::DrawArraysInstancedANGLE(
3421     GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3422   GPU_CLIENT_SINGLE_THREAD_CHECK();
3423   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3424       << GLES2Util::GetStringDrawMode(mode) << ", "
3425       << first << ", " << count << ", " << primcount << ")");
3426   if (count < 0) {
3427     SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3428     return;
3429   }
3430   if (primcount < 0) {
3431     SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3432     return;
3433   }
3434   if (primcount == 0) {
3435     return;
3436   }
3437   bool simulated = false;
3438   if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3439       "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3440       &simulated)) {
3441     return;
3442   }
3443   helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3444   RestoreArrayBuffer(simulated);
3445   CheckGLError();
3446 }
3447 
DrawElementsInstancedANGLE(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei primcount)3448 void GLES2Implementation::DrawElementsInstancedANGLE(
3449     GLenum mode, GLsizei count, GLenum type, const void* indices,
3450     GLsizei primcount) {
3451   GPU_CLIENT_SINGLE_THREAD_CHECK();
3452   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3453       << GLES2Util::GetStringDrawMode(mode) << ", "
3454       << count << ", "
3455       << GLES2Util::GetStringIndexType(type) << ", "
3456       << static_cast<const void*>(indices) << ", "
3457       << primcount << ")");
3458   if (count < 0) {
3459     SetGLError(GL_INVALID_VALUE,
3460                "glDrawElementsInstancedANGLE", "count less than 0.");
3461     return;
3462   }
3463   if (count == 0) {
3464     return;
3465   }
3466   if (primcount < 0) {
3467     SetGLError(GL_INVALID_VALUE,
3468                "glDrawElementsInstancedANGLE", "primcount < 0");
3469     return;
3470   }
3471   if (primcount == 0) {
3472     return;
3473   }
3474   GLuint offset = 0;
3475   bool simulated = false;
3476   if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3477       "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3478       indices, &offset, &simulated)) {
3479     return;
3480   }
3481   helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3482   RestoreElementAndArrayBuffers(simulated);
3483   CheckGLError();
3484 }
3485 
GenMailboxCHROMIUM(GLbyte * mailbox)3486 void GLES2Implementation::GenMailboxCHROMIUM(
3487     GLbyte* mailbox) {
3488   GPU_CLIENT_SINGLE_THREAD_CHECK();
3489   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3490       << static_cast<const void*>(mailbox) << ")");
3491   TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3492 
3493   std::vector<gpu::Mailbox> names;
3494   if (!gpu_control_->GenerateMailboxNames(1, &names)) {
3495     SetGLError(GL_OUT_OF_MEMORY, "glGenMailboxCHROMIUM", "Generate failed.");
3496     return;
3497   }
3498   memcpy(mailbox, names[0].name, GL_MAILBOX_SIZE_CHROMIUM);
3499 }
3500 
PushGroupMarkerEXT(GLsizei length,const GLchar * marker)3501 void GLES2Implementation::PushGroupMarkerEXT(
3502     GLsizei length, const GLchar* marker) {
3503   GPU_CLIENT_SINGLE_THREAD_CHECK();
3504   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3505       << length << ", " << marker << ")");
3506   if (!marker) {
3507     marker = "";
3508   }
3509   SetBucketAsString(
3510       kResultBucketId,
3511       (length ? std::string(marker, length) : std::string(marker)));
3512   helper_->PushGroupMarkerEXT(kResultBucketId);
3513   helper_->SetBucketSize(kResultBucketId, 0);
3514   debug_marker_manager_.PushGroup(
3515       length ? std::string(marker, length) : std::string(marker));
3516 }
3517 
InsertEventMarkerEXT(GLsizei length,const GLchar * marker)3518 void GLES2Implementation::InsertEventMarkerEXT(
3519     GLsizei length, const GLchar* marker) {
3520   GPU_CLIENT_SINGLE_THREAD_CHECK();
3521   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3522       << length << ", " << marker << ")");
3523   if (!marker) {
3524     marker = "";
3525   }
3526   SetBucketAsString(
3527       kResultBucketId,
3528       (length ? std::string(marker, length) : std::string(marker)));
3529   helper_->InsertEventMarkerEXT(kResultBucketId);
3530   helper_->SetBucketSize(kResultBucketId, 0);
3531   debug_marker_manager_.SetMarker(
3532       length ? std::string(marker, length) : std::string(marker));
3533 }
3534 
PopGroupMarkerEXT()3535 void GLES2Implementation::PopGroupMarkerEXT() {
3536   GPU_CLIENT_SINGLE_THREAD_CHECK();
3537   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3538   helper_->PopGroupMarkerEXT();
3539   debug_marker_manager_.PopGroup();
3540 }
3541 
TraceBeginCHROMIUM(const char * name)3542 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3543   GPU_CLIENT_SINGLE_THREAD_CHECK();
3544   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3545                  << name << ")");
3546   if (current_trace_name_.get()) {
3547     SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3548                "trace already running");
3549     return;
3550   }
3551   TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3552   SetBucketAsCString(kResultBucketId, name);
3553   helper_->TraceBeginCHROMIUM(kResultBucketId);
3554   helper_->SetBucketSize(kResultBucketId, 0);
3555   current_trace_name_.reset(new std::string(name));
3556 }
3557 
TraceEndCHROMIUM()3558 void GLES2Implementation::TraceEndCHROMIUM() {
3559   GPU_CLIENT_SINGLE_THREAD_CHECK();
3560   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3561   if (!current_trace_name_.get()) {
3562     SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3563                "missing begin trace");
3564     return;
3565   }
3566   helper_->TraceEndCHROMIUM();
3567   TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3568   current_trace_name_.reset();
3569 }
3570 
MapBufferCHROMIUM(GLuint target,GLenum access)3571 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3572   GPU_CLIENT_SINGLE_THREAD_CHECK();
3573   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3574       << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3575   switch (target)  {
3576     case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3577       if (access != GL_READ_ONLY) {
3578         SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3579         return NULL;
3580       }
3581       break;
3582     case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3583       if (access != GL_WRITE_ONLY) {
3584         SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3585         return NULL;
3586       }
3587       break;
3588     default:
3589       SetGLError(
3590           GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3591       return NULL;
3592   }
3593   GLuint buffer_id;
3594   GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3595   if (!buffer_id) {
3596     return NULL;
3597   }
3598   BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3599   if (!buffer) {
3600     SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3601     return NULL;
3602   }
3603   if (buffer->mapped()) {
3604     SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3605     return NULL;
3606   }
3607   // Here we wait for previous transfer operations to be finished.
3608   // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3609   // with this method of synchronization. Until this is fixed,
3610   // MapBufferCHROMIUM will not block even if the transfer is not ready
3611   // for these calls.
3612   if (buffer->transfer_ready_token()) {
3613     helper_->WaitForToken(buffer->transfer_ready_token());
3614     buffer->set_transfer_ready_token(0);
3615   }
3616   buffer->set_mapped(true);
3617 
3618   GPU_CLIENT_LOG("  returned " << buffer->address());
3619   CheckGLError();
3620   return buffer->address();
3621 }
3622 
UnmapBufferCHROMIUM(GLuint target)3623 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3624   GPU_CLIENT_SINGLE_THREAD_CHECK();
3625   GPU_CLIENT_LOG(
3626       "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3627   GLuint buffer_id;
3628   if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3629     SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3630   }
3631   if (!buffer_id) {
3632     return false;
3633   }
3634   BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3635   if (!buffer) {
3636     SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3637     return false;
3638   }
3639   if (!buffer->mapped()) {
3640     SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3641     return false;
3642   }
3643   buffer->set_mapped(false);
3644   CheckGLError();
3645   return true;
3646 }
3647 
AsyncTexImage2DCHROMIUM(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)3648 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3649     GLenum target, GLint level, GLint internalformat, GLsizei width,
3650     GLsizei height, GLint border, GLenum format, GLenum type,
3651     const void* pixels) {
3652   GPU_CLIENT_SINGLE_THREAD_CHECK();
3653   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3654       << GLES2Util::GetStringTextureTarget(target) << ", "
3655       << level << ", "
3656       << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3657       << width << ", " << height << ", " << border << ", "
3658       << GLES2Util::GetStringTextureFormat(format) << ", "
3659       << GLES2Util::GetStringPixelType(type) << ", "
3660       << static_cast<const void*>(pixels) << ")");
3661   if (level < 0 || height < 0 || width < 0) {
3662     SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3663     return;
3664   }
3665   uint32 size;
3666   uint32 unpadded_row_size;
3667   uint32 padded_row_size;
3668   if (!GLES2Util::ComputeImageDataSizes(
3669           width, height, format, type, unpack_alignment_, &size,
3670           &unpadded_row_size, &padded_row_size)) {
3671     SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3672     return;
3673   }
3674 
3675   // If there's no data/buffer just issue the AsyncTexImage2D
3676   if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3677     helper_->AsyncTexImage2DCHROMIUM(
3678        target, level, internalformat, width, height, border, format, type,
3679        0, 0);
3680     return;
3681   }
3682 
3683   // Otherwise, async uploads require a transfer buffer to be bound.
3684   // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3685   // the buffer before the transfer is finished. (Currently such
3686   // synchronization has to be handled manually.)
3687   GLuint offset = ToGLuint(pixels);
3688   BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3689       bound_pixel_unpack_transfer_buffer_id_,
3690       "glAsyncTexImage2DCHROMIUM", offset, size);
3691   if (buffer && buffer->shm_id() != -1) {
3692     helper_->AsyncTexImage2DCHROMIUM(
3693         target, level, internalformat, width, height, border, format, type,
3694         buffer->shm_id(), buffer->shm_offset() + offset);
3695   }
3696 }
3697 
AsyncTexSubImage2DCHROMIUM(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)3698 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3699     GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3700     GLsizei height, GLenum format, GLenum type, const void* pixels) {
3701   GPU_CLIENT_SINGLE_THREAD_CHECK();
3702   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3703       << GLES2Util::GetStringTextureTarget(target) << ", "
3704       << level << ", "
3705       << xoffset << ", " << yoffset << ", "
3706       << width << ", " << height << ", "
3707       << GLES2Util::GetStringTextureFormat(format) << ", "
3708       << GLES2Util::GetStringPixelType(type) << ", "
3709       << static_cast<const void*>(pixels) << ")");
3710   if (level < 0 || height < 0 || width < 0) {
3711     SetGLError(
3712         GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3713     return;
3714   }
3715 
3716   uint32 size;
3717   uint32 unpadded_row_size;
3718   uint32 padded_row_size;
3719   if (!GLES2Util::ComputeImageDataSizes(
3720         width, height, format, type, unpack_alignment_, &size,
3721         &unpadded_row_size, &padded_row_size)) {
3722     SetGLError(
3723         GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3724     return;
3725   }
3726 
3727   // Async uploads require a transfer buffer to be bound.
3728   // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3729   // the buffer before the transfer is finished. (Currently such
3730   // synchronization has to be handled manually.)
3731   GLuint offset = ToGLuint(pixels);
3732   BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3733       bound_pixel_unpack_transfer_buffer_id_,
3734       "glAsyncTexSubImage2DCHROMIUM", offset, size);
3735   if (buffer && buffer->shm_id() != -1) {
3736     helper_->AsyncTexSubImage2DCHROMIUM(
3737         target, level, xoffset, yoffset, width, height, format, type,
3738         buffer->shm_id(), buffer->shm_offset() + offset);
3739   }
3740 }
3741 
WaitAsyncTexImage2DCHROMIUM(GLenum target)3742 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3743   GPU_CLIENT_SINGLE_THREAD_CHECK();
3744   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3745       << GLES2Util::GetStringTextureTarget(target) << ")");
3746   helper_->WaitAsyncTexImage2DCHROMIUM(target);
3747   CheckGLError();
3748 }
3749 
InsertSyncPointCHROMIUM()3750 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3751   GPU_CLIENT_SINGLE_THREAD_CHECK();
3752   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3753   helper_->CommandBufferHelper::Flush();
3754   return gpu_control_->InsertSyncPoint();
3755 }
3756 
CreateImageCHROMIUMHelper(GLsizei width,GLsizei height,GLenum internalformat)3757 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3758     GLsizei width, GLsizei height, GLenum internalformat) {
3759   if (width <= 0) {
3760     SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3761     return 0;
3762   }
3763 
3764   if (height <= 0) {
3765     SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3766     return 0;
3767   }
3768   // Flush the command stream to ensure ordering in case the newly
3769   // returned image_id has recently been in use with a different buffer.
3770   helper_->CommandBufferHelper::Flush();
3771 
3772   // Create new buffer.
3773   GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3774       width, height, internalformat);
3775   if (buffer_id == 0) {
3776     SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3777     return 0;
3778   }
3779   return buffer_id;
3780 }
3781 
CreateImageCHROMIUM(GLsizei width,GLsizei height,GLenum internalformat)3782 GLuint GLES2Implementation::CreateImageCHROMIUM(
3783     GLsizei width, GLsizei height, GLenum internalformat) {
3784   GPU_CLIENT_SINGLE_THREAD_CHECK();
3785   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3786       << width << ", "
3787       << height << ", "
3788       << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3789   GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3790   CheckGLError();
3791   return image_id;
3792 }
3793 
DestroyImageCHROMIUMHelper(GLuint image_id)3794 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3795   gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3796       image_id);
3797   if (!gpu_buffer) {
3798     SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3799     return;
3800   }
3801 
3802   // Flush the command stream to make sure all pending commands
3803   // that may refer to the image_id are executed on the service side.
3804   helper_->CommandBufferHelper::Flush();
3805   gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3806 }
3807 
DestroyImageCHROMIUM(GLuint image_id)3808 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3809   GPU_CLIENT_SINGLE_THREAD_CHECK();
3810   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3811       << image_id << ")");
3812   DestroyImageCHROMIUMHelper(image_id);
3813   CheckGLError();
3814 }
3815 
UnmapImageCHROMIUMHelper(GLuint image_id)3816 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3817   gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3818       image_id);
3819   if (!gpu_buffer) {
3820     SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3821     return;
3822   }
3823 
3824   if (!gpu_buffer->IsMapped()) {
3825     SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3826     return;
3827   }
3828   gpu_buffer->Unmap();
3829 }
3830 
UnmapImageCHROMIUM(GLuint image_id)3831 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3832   GPU_CLIENT_SINGLE_THREAD_CHECK();
3833   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3834        << image_id << ")");
3835 
3836   UnmapImageCHROMIUMHelper(image_id);
3837   CheckGLError();
3838 }
3839 
MapImageCHROMIUMHelper(GLuint image_id,GLenum access)3840 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3841                                                   GLenum access) {
3842   gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3843       image_id);
3844   if (!gpu_buffer) {
3845     SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3846     return NULL;
3847   }
3848   gfx::GpuMemoryBuffer::AccessMode mode;
3849   switch(access) {
3850     case GL_WRITE_ONLY:
3851       mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3852       break;
3853     case GL_READ_ONLY:
3854       mode = gfx::GpuMemoryBuffer::READ_ONLY;
3855       break;
3856     case GL_READ_WRITE:
3857       mode = gfx::GpuMemoryBuffer::READ_WRITE;
3858       break;
3859     default:
3860       SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3861                  "invalid GPU access mode");
3862       return NULL;
3863   }
3864 
3865   if (gpu_buffer->IsMapped()) {
3866     SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3867     return NULL;
3868   }
3869 
3870   void* mapped_buffer = NULL;
3871   gpu_buffer->Map(mode, &mapped_buffer);
3872   return mapped_buffer;
3873 }
3874 
MapImageCHROMIUM(GLuint image_id,GLenum access)3875 void* GLES2Implementation::MapImageCHROMIUM(
3876     GLuint image_id, GLenum access) {
3877   GPU_CLIENT_SINGLE_THREAD_CHECK();
3878   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3879       << image_id << ", "
3880       << GLES2Util::GetStringEnum(access) << ")");
3881 
3882   void* mapped = MapImageCHROMIUMHelper(image_id, access);
3883   CheckGLError();
3884   return mapped;
3885 }
3886 
GetImageParameterivCHROMIUMHelper(GLuint image_id,GLenum pname,GLint * params)3887 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3888     GLuint image_id, GLenum pname, GLint* params) {
3889   if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3890     SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3891                "invalid parameter");
3892     return;
3893   }
3894 
3895   gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3896       image_id);
3897   if (!gpu_buffer) {
3898     SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3899                "invalid image");
3900     return;
3901   }
3902 
3903   *params = gpu_buffer->GetStride();
3904 }
3905 
GetImageParameterivCHROMIUM(GLuint image_id,GLenum pname,GLint * params)3906 void GLES2Implementation::GetImageParameterivCHROMIUM(
3907     GLuint image_id, GLenum pname, GLint* params) {
3908   GPU_CLIENT_SINGLE_THREAD_CHECK();
3909   GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3910   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3911       << image_id << ", "
3912       << GLES2Util::GetStringBufferParameter(pname) << ", "
3913       << static_cast<const void*>(params) << ")");
3914   GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3915   CheckGLError();
3916 }
3917 
3918 // Include the auto-generated part of this file. We split this because it means
3919 // we can easily edit the non-auto generated parts right here in this file
3920 // instead of having to edit some template or the code generator.
3921 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3922 
3923 }  // namespace gles2
3924 }  // namespace gpu
3925