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