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/gl2.h>
10 #include <GLES2/gl2ext.h>
11 #include <GLES2/gl2extchromium.h>
12 #include <GLES3/gl3.h>
13 #include <GLES3/gl31.h>
14 #include <stddef.h>
15 #include <stdint.h>
16
17 #include <algorithm>
18 #include <map>
19 #include <set>
20 #include <sstream>
21 #include <string>
22
23 #include "base/atomic_sequence_num.h"
24 #include "base/bind.h"
25 #include "base/bits.h"
26 #include "base/compiler_specific.h"
27 #include "base/containers/span.h"
28 #include "base/numerics/safe_math.h"
29 #include "base/stl_util.h"
30 #include "base/strings/string_split.h"
31 #include "base/strings/stringprintf.h"
32 #include "base/system/sys_info.h"
33 #include "base/threading/thread_task_runner_handle.h"
34 #include "base/trace_event/memory_allocator_dump.h"
35 #include "base/trace_event/memory_dump_manager.h"
36 #include "base/trace_event/process_memory_dump.h"
37 #include "base/trace_event/trace_event.h"
38 #include "build/build_config.h"
39 #include "gpu/command_buffer/client/buffer_tracker.h"
40 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
41 #include "gpu/command_buffer/client/gpu_control.h"
42 #include "gpu/command_buffer/client/program_info_manager.h"
43 #include "gpu/command_buffer/client/query_tracker.h"
44 #include "gpu/command_buffer/client/readback_buffer_shadow_tracker.h"
45 #include "gpu/command_buffer/client/shared_memory_limits.h"
46 #include "gpu/command_buffer/client/transfer_buffer.h"
47 #include "gpu/command_buffer/client/transfer_buffer_cmd_copy_helpers.h"
48 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
49 #include "gpu/command_buffer/common/context_creation_attribs.h"
50 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
51 #include "gpu/command_buffer/common/id_allocator.h"
52 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
53 #include "gpu/command_buffer/common/sync_token.h"
54 #include "ui/gfx/geometry/rect.h"
55 #include "ui/gfx/geometry/rect_f.h"
56 #include "ui/gl/gpu_preference.h"
57
58 #if !defined(__native_client__)
59 #include "ui/gfx/color_space.h"
60 #include "ui/gfx/ipc/color/gfx_param_traits.h"
61 #endif
62
63 #if defined(GPU_CLIENT_DEBUG)
64 #define GPU_CLIENT_SINGLE_THREAD_CHECK() \
65 DeferErrorCallbacks deferrer(this); \
66 SingleThreadChecker checker(this);
67 #else // !defined(GPU_CLIENT_DEBUG)
68 #define GPU_CLIENT_SINGLE_THREAD_CHECK() DeferErrorCallbacks deferrer(this);
69 #endif // defined(GPU_CLIENT_DEBUG)
70
71 // Check that destination pointers point to initialized memory.
72 // When the context is lost, calling GL function has no effect so if destination
73 // pointers point to initialized memory it can often lead to crash bugs. eg.
74 //
75 // GLsizei len;
76 // glGetShaderSource(shader, max_size, &len, buffer);
77 // std::string src(buffer, buffer + len); // len can be uninitialized here!!!
78 //
79 // Because this check is not official GL this check happens only on Chrome code,
80 // not Pepper.
81 //
82 // If it was up to us we'd just always write to the destination but the OpenGL
83 // spec defines the behavior of OpenGL functions, not us. :-(
84 #if defined(__native_client__) || defined(GLES2_CONFORMANCE_TESTS)
85 #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v)
86 #define GPU_CLIENT_DCHECK(v)
87 #elif defined(GPU_DCHECK)
88 #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) GPU_DCHECK(v)
89 #define GPU_CLIENT_DCHECK(v) GPU_DCHECK(v)
90 #elif defined(DCHECK)
91 #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) DCHECK(v)
92 #define GPU_CLIENT_DCHECK(v) DCHECK(v)
93 #else
94 #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) ASSERT(v)
95 #define GPU_CLIENT_DCHECK(v) ASSERT(v)
96 #endif
97
98 #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(type, ptr) \
99 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT( \
100 ptr && \
101 (ptr[0] == static_cast<type>(0) || ptr[0] == static_cast<type>(-1)));
102
103 #define GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(type, ptr) \
104 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT( \
105 !ptr || \
106 (ptr[0] == static_cast<type>(0) || ptr[0] == static_cast<type>(-1)));
107
108 namespace gpu {
109 namespace gles2 {
110
111 namespace {
112
CopyRectToBuffer(const void * pixels,uint32_t height,uint32_t unpadded_row_size,uint32_t pixels_padded_row_size,void * buffer,uint32_t buffer_padded_row_size)113 void CopyRectToBuffer(const void* pixels,
114 uint32_t height,
115 uint32_t unpadded_row_size,
116 uint32_t pixels_padded_row_size,
117 void* buffer,
118 uint32_t buffer_padded_row_size) {
119 if (height == 0)
120 return;
121 const int8_t* source = static_cast<const int8_t*>(pixels);
122 int8_t* dest = static_cast<int8_t*>(buffer);
123 if (pixels_padded_row_size != buffer_padded_row_size) {
124 for (uint32_t ii = 0; ii < height; ++ii) {
125 memcpy(dest, source, unpadded_row_size);
126 dest += buffer_padded_row_size;
127 source += pixels_padded_row_size;
128 }
129 } else {
130 uint32_t size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
131 memcpy(dest, source, size);
132 }
133 }
134
135 static base::AtomicSequenceNumber g_flush_id;
136
GenerateNextFlushId()137 uint32_t GenerateNextFlushId() {
138 return static_cast<uint32_t>(g_flush_id.GetNext());
139 }
140
IsReadbackUsage(GLenum usage)141 bool IsReadbackUsage(GLenum usage) {
142 return usage == GL_STREAM_READ || usage == GL_DYNAMIC_READ ||
143 usage == GL_STATIC_READ;
144 }
145
146 } // anonymous namespace
147
148 GLES2Implementation::GLStaticState::GLStaticState() = default;
149
150 GLES2Implementation::GLStaticState::~GLStaticState() = default;
151
DeferErrorCallbacks(GLES2Implementation * gles2_implementation)152 GLES2Implementation::DeferErrorCallbacks::DeferErrorCallbacks(
153 GLES2Implementation* gles2_implementation)
154 : gles2_implementation_(gles2_implementation) {
155 DCHECK_EQ(false, gles2_implementation_->deferring_error_callbacks_);
156 gles2_implementation_->deferring_error_callbacks_ = true;
157 }
158
~DeferErrorCallbacks()159 GLES2Implementation::DeferErrorCallbacks::~DeferErrorCallbacks() {
160 DCHECK_EQ(true, gles2_implementation_->deferring_error_callbacks_);
161 gles2_implementation_->deferring_error_callbacks_ = false;
162 gles2_implementation_->CallDeferredErrorCallbacks();
163 }
164
DeferredErrorCallback(std::string message,int32_t id)165 GLES2Implementation::DeferredErrorCallback::DeferredErrorCallback(
166 std::string message,
167 int32_t id)
168 : message(std::move(message)), id(id) {}
169
SingleThreadChecker(GLES2Implementation * gles2_implementation)170 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
171 GLES2Implementation* gles2_implementation)
172 : gles2_implementation_(gles2_implementation) {
173 CHECK_EQ(0, gles2_implementation_->use_count_);
174 ++gles2_implementation_->use_count_;
175 }
176
~SingleThreadChecker()177 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
178 --gles2_implementation_->use_count_;
179 CHECK_EQ(0, gles2_implementation_->use_count_);
180 }
181
GLES2Implementation(GLES2CmdHelper * helper,scoped_refptr<ShareGroup> share_group,TransferBufferInterface * transfer_buffer,bool bind_generates_resource,bool lose_context_when_out_of_memory,bool support_client_side_arrays,GpuControl * gpu_control)182 GLES2Implementation::GLES2Implementation(
183 GLES2CmdHelper* helper,
184 scoped_refptr<ShareGroup> share_group,
185 TransferBufferInterface* transfer_buffer,
186 bool bind_generates_resource,
187 bool lose_context_when_out_of_memory,
188 bool support_client_side_arrays,
189 GpuControl* gpu_control)
190 : ImplementationBase(helper, transfer_buffer, gpu_control),
191 helper_(helper),
192 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
193 pack_alignment_(4),
194 pack_row_length_(0),
195 pack_skip_pixels_(0),
196 pack_skip_rows_(0),
197 unpack_alignment_(4),
198 unpack_row_length_(0),
199 unpack_image_height_(0),
200 unpack_skip_rows_(0),
201 unpack_skip_pixels_(0),
202 unpack_skip_images_(0),
203 active_texture_unit_(0),
204 bound_framebuffer_(0),
205 bound_read_framebuffer_(0),
206 bound_renderbuffer_(0),
207 current_program_(0),
208 bound_array_buffer_(0),
209 bound_atomic_counter_buffer_(0),
210 bound_copy_read_buffer_(0),
211 bound_copy_write_buffer_(0),
212 bound_dispatch_indirect_buffer_(0),
213 bound_draw_indirect_buffer_(0),
214 bound_pixel_pack_buffer_(0),
215 bound_pixel_unpack_buffer_(0),
216 bound_shader_storage_buffer_(0),
217 bound_transform_feedback_buffer_(0),
218 bound_uniform_buffer_(0),
219 bound_pixel_pack_transfer_buffer_id_(0),
220 bound_pixel_unpack_transfer_buffer_id_(0),
221 error_bits_(0),
222 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
223 support_client_side_arrays_(support_client_side_arrays),
224 use_count_(0),
225 flush_id_(0),
226 max_extra_transfer_buffer_size_(0),
227 current_trace_stack_(0),
228 aggressively_free_resources_(false),
229 cached_extension_string_(nullptr) {
230 DCHECK(helper);
231
232 std::stringstream ss;
233 ss << std::hex << this;
234 this_in_hex_ = ss.str();
235
236 share_group_ =
237 (share_group ? std::move(share_group)
238 : new ShareGroup(
239 bind_generates_resource,
240 gpu_control_->GetCommandBufferID().GetUnsafeValue()));
241 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
242
243 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
244 }
245
Initialize(const SharedMemoryLimits & limits)246 gpu::ContextResult GLES2Implementation::Initialize(
247 const SharedMemoryLimits& limits) {
248 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
249 auto result = ImplementationBase::Initialize(limits);
250 if (result != gpu::ContextResult::kSuccess) {
251 return result;
252 }
253
254 max_extra_transfer_buffer_size_ = limits.max_mapped_memory_for_texture_upload;
255
256 GLStaticState::ShaderPrecisionMap* shader_precisions =
257 &static_state_.shader_precisions;
258 capabilities_.VisitPrecisions(
259 [shader_precisions](GLenum shader, GLenum type,
260 Capabilities::ShaderPrecision* result) {
261 const GLStaticState::ShaderPrecisionKey key(shader, type);
262 cmds::GetShaderPrecisionFormat::Result cached_result = {
263 true, result->min_range, result->max_range, result->precision};
264 shader_precisions->insert(std::make_pair(key, cached_result));
265 });
266
267 util_.set_num_compressed_texture_formats(
268 capabilities_.num_compressed_texture_formats);
269 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
270
271 texture_units_ = std::make_unique<TextureUnit[]>(
272 capabilities_.max_combined_texture_image_units);
273
274 buffer_tracker_ = std::make_unique<BufferTracker>(mapped_memory_.get());
275 readback_buffer_shadow_tracker_ =
276 std::make_unique<ReadbackBufferShadowTracker>(mapped_memory_.get(),
277 helper_);
278
279 for (int i = 0; i < static_cast<int>(IdNamespaces::kNumIdNamespaces); ++i)
280 id_allocators_[i].reset(new IdAllocator());
281
282 if (support_client_side_arrays_) {
283 GetIdHandler(SharedIdNamespaces::kBuffers)
284 ->MakeIds(this, kClientSideArrayId, base::size(reserved_ids_),
285 &reserved_ids_[0]);
286 }
287
288 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
289 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
290 support_client_side_arrays_));
291
292 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
293 // on Client & Service.
294 if (capabilities_.bind_generates_resource_chromium !=
295 (share_group_->bind_generates_resource() ? 1 : 0)) {
296 SetGLError(GL_INVALID_OPERATION, "Initialize",
297 "Service bind_generates_resource mismatch.");
298 LOG(ERROR) << "ContextResult::kFatalFailure: "
299 << "bind_generates_resource mismatch";
300 return gpu::ContextResult::kFatalFailure;
301 }
302
303 return gpu::ContextResult::kSuccess;
304 }
305
~GLES2Implementation()306 GLES2Implementation::~GLES2Implementation() {
307 // Make sure the queries are finished otherwise we'll delete the
308 // shared memory (mapped_memory_) which will free the memory used
309 // by the queries. The GPU process when validating that memory is still
310 // shared will fail and abort (ie, it will stop running).
311 WaitForCmd();
312
313 query_tracker_.reset();
314
315 // GLES2Implementation::Initialize() could fail before allocating
316 // reserved_ids_, so we need delete them carefully.
317 if (support_client_side_arrays_ && reserved_ids_[0]) {
318 DeleteBuffers(base::size(reserved_ids_), &reserved_ids_[0]);
319 }
320
321 // Release remaining BufferRange mem; This is when a MapBufferRange() is
322 // called but not the UnmapBuffer() pair.
323 ClearMappedBufferRangeMap();
324
325 // Release any per-context data in share group.
326 share_group_->FreeContext(this);
327
328 buffer_tracker_.reset();
329 readback_buffer_shadow_tracker_.reset();
330
331 // Make sure the commands make it the service.
332 WaitForCmd();
333 }
334
helper() const335 GLES2CmdHelper* GLES2Implementation::helper() const {
336 return helper_;
337 }
338
GetIdHandler(SharedIdNamespaces namespace_id) const339 IdHandlerInterface* GLES2Implementation::GetIdHandler(
340 SharedIdNamespaces namespace_id) const {
341 return share_group_->GetIdHandler(namespace_id);
342 }
343
GetRangeIdHandler(int namespace_id) const344 RangeIdHandlerInterface* GLES2Implementation::GetRangeIdHandler(
345 int namespace_id) const {
346 return share_group_->GetRangeIdHandler(namespace_id);
347 }
348
GetIdAllocator(IdNamespaces namespace_id) const349 IdAllocator* GLES2Implementation::GetIdAllocator(
350 IdNamespaces namespace_id) const {
351 return id_allocators_[static_cast<int>(namespace_id)].get();
352 }
353
OnGpuControlLostContext()354 void GLES2Implementation::OnGpuControlLostContext() {
355 // This should never occur more than once.
356 DCHECK(!lost_context_callback_run_);
357 lost_context_callback_run_ = true;
358 share_group_->Lose();
359 if (!lost_context_callback_.is_null()) {
360 std::move(lost_context_callback_).Run();
361 }
362 }
363
OnGpuControlLostContextMaybeReentrant()364 void GLES2Implementation::OnGpuControlLostContextMaybeReentrant() {
365 // Queries for lost context state should immediately reflect reality,
366 // but don't call out to clients yet to avoid them re-entering this
367 // class.
368 share_group_->Lose();
369 }
370
OnGpuControlErrorMessage(const char * message,int32_t id)371 void GLES2Implementation::OnGpuControlErrorMessage(const char* message,
372 int32_t id) {
373 SendErrorMessage(message, id);
374 }
375
OnGpuControlSwapBuffersCompleted(const SwapBuffersCompleteParams & params)376 void GLES2Implementation::OnGpuControlSwapBuffersCompleted(
377 const SwapBuffersCompleteParams& params) {
378 auto found = pending_swap_callbacks_.find(params.swap_response.swap_id);
379 if (found == pending_swap_callbacks_.end())
380 return;
381
382 // Erase the entry before running the callback to guard against the callback
383 // mutating the |pending_swap_callbacks_|.
384 auto callback = std::move(found->second);
385 pending_swap_callbacks_.erase(found);
386
387 std::move(callback).Run(params);
388 }
389
OnGpuSwitched(gl::GpuPreference active_gpu_heuristic)390 void GLES2Implementation::OnGpuSwitched(
391 gl::GpuPreference active_gpu_heuristic) {
392 gpu_switched_ = true;
393 active_gpu_heuristic_ = active_gpu_heuristic;
394 }
395
DidGpuSwitch(gl::GpuPreference * active_gpu)396 GLboolean GLES2Implementation::DidGpuSwitch(gl::GpuPreference* active_gpu) {
397 if (gpu_switched_) {
398 *active_gpu = active_gpu_heuristic_;
399 }
400 GLboolean result = gpu_switched_ ? GL_TRUE : GL_FALSE;
401 gpu_switched_ = false;
402 return result;
403 }
404
SendErrorMessage(std::string message,int32_t id)405 void GLES2Implementation::SendErrorMessage(std::string message, int32_t id) {
406 if (error_message_callback_.is_null())
407 return;
408
409 if (deferring_error_callbacks_) {
410 deferred_error_callbacks_.emplace_back(std::move(message), id);
411 return;
412 }
413
414 error_message_callback_.Run(message.c_str(), id);
415 }
416
CallDeferredErrorCallbacks()417 void GLES2Implementation::CallDeferredErrorCallbacks() {
418 if (deferred_error_callbacks_.empty())
419 return;
420
421 if (error_message_callback_.is_null()) {
422 // User probably cleared this out.
423 deferred_error_callbacks_.clear();
424 return;
425 }
426
427 std::deque<DeferredErrorCallback> local_callbacks;
428 std::swap(deferred_error_callbacks_, local_callbacks);
429 for (auto c : local_callbacks) {
430 error_message_callback_.Run(c.message.c_str(), c.id);
431 }
432 }
433
OnSwapBufferPresented(uint64_t swap_id,const gfx::PresentationFeedback & feedback)434 void GLES2Implementation::OnSwapBufferPresented(
435 uint64_t swap_id,
436 const gfx::PresentationFeedback& feedback) {
437 auto found = pending_presentation_callbacks_.find(swap_id);
438 if (found == pending_presentation_callbacks_.end())
439 return;
440
441 // Erase the entry before running the callback to guard against the callback
442 // mutating the |pending_presentation_callbacks_|.
443 auto callback = std::move(found->second);
444 pending_presentation_callbacks_.erase(found);
445
446 std::move(callback).Run(feedback);
447 }
448
OnGpuControlReturnData(base::span<const uint8_t> data)449 void GLES2Implementation::OnGpuControlReturnData(
450 base::span<const uint8_t> data) {
451 NOTIMPLEMENTED();
452 }
453
FreeSharedMemory(void * mem)454 void GLES2Implementation::FreeSharedMemory(void* mem) {
455 mapped_memory_->FreePendingToken(mem, helper_->InsertToken());
456 }
457
CreateGpuFenceCHROMIUM()458 GLuint GLES2Implementation::CreateGpuFenceCHROMIUM() {
459 GLuint client_id = GetIdAllocator(IdNamespaces::kGpuFences)
460 ->AllocateIDAtOrAbove(last_gpu_fence_id_ + 1);
461 // Out of paranoia, don't allow IDs to wrap around to avoid potential
462 // collisions on reuse. The space of 2^32 IDs is enough for over a year of
463 // allocating two per frame at 60fps. TODO(crbug.com/790550): Revisit if this
464 // is an issue, for example by deferring ID release if they would be reissued
465 // too soon.
466 CHECK(client_id > last_gpu_fence_id_) << "ID wrap prevented";
467 last_gpu_fence_id_ = client_id;
468 helper_->CreateGpuFenceINTERNAL(client_id);
469 GPU_CLIENT_LOG("returned " << client_id);
470 CheckGLError();
471 return client_id;
472 }
473
CreateClientGpuFenceCHROMIUM(ClientGpuFence source)474 GLuint GLES2Implementation::CreateClientGpuFenceCHROMIUM(
475 ClientGpuFence source) {
476 GLuint client_id = GetIdAllocator(IdNamespaces::kGpuFences)
477 ->AllocateIDAtOrAbove(last_gpu_fence_id_ + 1);
478 // See CreateGpuFenceCHROMIUM comment re wraparound.
479 CHECK(client_id > last_gpu_fence_id_) << "ID wrap prevented";
480 last_gpu_fence_id_ = client_id;
481
482 // Create the service-side GpuFenceEntry via gpu_control. This is guaranteed
483 // to arrive before any future GL helper_ commands on this stream, so it's
484 // safe to use the client_id generated here in following commands such as
485 // WaitGpuFenceCHROMIUM without explicit flushing.
486 gpu_control_->CreateGpuFence(client_id, source);
487
488 GPU_CLIENT_LOG("returned " << client_id);
489 CheckGLError();
490 return client_id;
491 }
492
DestroyGpuFenceCHROMIUMHelper(GLuint client_id)493 void GLES2Implementation::DestroyGpuFenceCHROMIUMHelper(GLuint client_id) {
494 if (GetIdAllocator(IdNamespaces::kGpuFences)->InUse(client_id)) {
495 GetIdAllocator(IdNamespaces::kGpuFences)->FreeID(client_id);
496 helper_->DestroyGpuFenceCHROMIUM(client_id);
497 } else {
498 SetGLError(GL_INVALID_VALUE, "glDestroyGpuFenceCHROMIUM",
499 "id not created by this context.");
500 }
501 }
502
SetAggressivelyFreeResources(bool aggressively_free_resources)503 void GLES2Implementation::SetAggressivelyFreeResources(
504 bool aggressively_free_resources) {
505 TRACE_EVENT1("gpu", "GLES2Implementation::SetAggressivelyFreeResources",
506 "aggressively_free_resources", aggressively_free_resources);
507 aggressively_free_resources_ = aggressively_free_resources;
508
509 if (aggressively_free_resources_ && helper_->HaveRingBuffer()) {
510 // Ensure that we clean up as much cache memory as possible and fully flush.
511 FlushDriverCachesCHROMIUM();
512
513 // Flush will delete transfer buffer resources if
514 // |aggressively_free_resources_| is true.
515 Flush();
516 } else {
517 ShallowFlushCHROMIUM();
518 }
519 }
520
IsExtensionAvailable(const char * ext)521 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
522 const char* extensions =
523 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
524 if (!extensions)
525 return false;
526
527 int length = strlen(ext);
528 while (true) {
529 int n = strcspn(extensions, " ");
530 if (n == length && 0 == strncmp(ext, extensions, length)) {
531 return true;
532 }
533 if ('\0' == extensions[n]) {
534 return false;
535 }
536 extensions += n + 1;
537 }
538 }
539
IsExtensionAvailableHelper(const char * extension,ExtensionStatus * status)540 bool GLES2Implementation::IsExtensionAvailableHelper(const char* extension,
541 ExtensionStatus* status) {
542 switch (*status) {
543 case kAvailableExtensionStatus:
544 return true;
545 case kUnavailableExtensionStatus:
546 return false;
547 default: {
548 bool available = IsExtensionAvailable(extension);
549 *status =
550 available ? kAvailableExtensionStatus : kUnavailableExtensionStatus;
551 return available;
552 }
553 }
554 }
555
IsChromiumFramebufferMultisampleAvailable()556 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
557 return IsExtensionAvailableHelper("GL_CHROMIUM_framebuffer_multisample",
558 &chromium_framebuffer_multisample_);
559 }
560
GetLogPrefix() const561 const std::string& GLES2Implementation::GetLogPrefix() const {
562 const std::string& prefix(debug_marker_manager_.GetMarker());
563 return prefix.empty() ? this_in_hex_ : prefix;
564 }
565
GetError()566 GLenum GLES2Implementation::GetError() {
567 GPU_CLIENT_SINGLE_THREAD_CHECK();
568 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
569 GLenum err = GetGLError();
570 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
571 return err;
572 }
573
GetGLError()574 GLenum GLES2Implementation::GetGLError() {
575 TRACE_EVENT0("gpu", "GLES2::GetGLError");
576 // Check the GL error first, then our wrapped error.
577 typedef cmds::GetError::Result Result;
578 auto result = GetResultAs<Result>();
579 // If we couldn't allocate a result the context is lost.
580 if (!result) {
581 return GL_NO_ERROR;
582 }
583 *result = GL_NO_ERROR;
584 helper_->GetError(GetResultShmId(), result.offset());
585 WaitForCmd();
586 GLenum error = *result;
587 if (error == GL_NO_ERROR) {
588 error = GetClientSideGLError();
589 } else {
590 // There was an error, clear the corresponding wrapped error.
591 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
592 }
593 return error;
594 }
595
596 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
FailGLError(GLenum error)597 void GLES2Implementation::FailGLError(GLenum error) {
598 if (error != GL_NO_ERROR) {
599 NOTREACHED() << "Error";
600 }
601 }
602 // NOTE: Calling GetGLError overwrites data in the result buffer.
CheckGLError()603 void GLES2Implementation::CheckGLError() {
604 FailGLError(GetGLError());
605 }
606 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
607
SetGLError(GLenum error,const char * function_name,const char * msg)608 void GLES2Implementation::SetGLError(GLenum error,
609 const char* function_name,
610 const char* msg) {
611 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
612 << GLES2Util::GetStringError(error) << ": "
613 << function_name << ": " << msg);
614 FailGLError(error);
615 if (msg) {
616 last_error_ = msg;
617 }
618 if (!error_message_callback_.is_null()) {
619 std::string temp(GLES2Util::GetStringError(error) + " : " + function_name +
620 ": " + (msg ? msg : ""));
621 SendErrorMessage(temp.c_str(), 0);
622 }
623 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
624
625 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
626 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
627 GL_UNKNOWN_CONTEXT_RESET_ARB);
628 }
629 }
630
SetGLErrorInvalidEnum(const char * function_name,GLenum value,const char * label)631 void GLES2Implementation::SetGLErrorInvalidEnum(const char* function_name,
632 GLenum value,
633 const char* label) {
634 SetGLError(
635 GL_INVALID_ENUM, function_name,
636 (std::string(label) + " was " + GLES2Util::GetStringEnum(value)).c_str());
637 }
638
Disable(GLenum cap)639 void GLES2Implementation::Disable(GLenum cap) {
640 GPU_CLIENT_SINGLE_THREAD_CHECK();
641 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
642 << GLES2Util::GetStringCapability(cap) << ")");
643 bool changed = false;
644 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
645 helper_->Disable(cap);
646 }
647 CheckGLError();
648 }
649
Enable(GLenum cap)650 void GLES2Implementation::Enable(GLenum cap) {
651 GPU_CLIENT_SINGLE_THREAD_CHECK();
652 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
653 << GLES2Util::GetStringCapability(cap) << ")");
654 bool changed = false;
655 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
656 helper_->Enable(cap);
657 }
658 CheckGLError();
659 }
660
IsEnabled(GLenum cap)661 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
662 GPU_CLIENT_SINGLE_THREAD_CHECK();
663 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
664 << GLES2Util::GetStringCapability(cap) << ")");
665 bool state = false;
666 if (!state_.GetEnabled(cap, &state)) {
667 typedef cmds::IsEnabled::Result Result;
668 auto result = GetResultAs<Result>();
669 if (!result) {
670 return GL_FALSE;
671 }
672 *result = 0;
673 helper_->IsEnabled(cap, GetResultShmId(), result.offset());
674 WaitForCmd();
675 state = (*result) != 0;
676 }
677
678 GPU_CLIENT_LOG("returned " << state);
679 CheckGLError();
680 return state;
681 }
682
GetHelper(GLenum pname,GLint * params)683 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
684 // TODO(zmo): For all the BINDING points, there is a possibility where
685 // resources are shared among multiple contexts, that the cached points
686 // are invalid. It is not a problem for now, but once we allow resource
687 // sharing in WebGL, we need to implement a mechanism to allow correct
688 // client side binding points tracking. crbug.com/465562.
689
690 // ES2 parameters.
691 switch (pname) {
692 case GL_ACTIVE_TEXTURE:
693 *params = active_texture_unit_ + GL_TEXTURE0;
694 return true;
695 case GL_ARRAY_BUFFER_BINDING:
696 *params = bound_array_buffer_;
697 return true;
698 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
699 *params = vertex_array_object_manager_->bound_element_array_buffer();
700 return true;
701 case GL_FRAMEBUFFER_BINDING:
702 *params = bound_framebuffer_;
703 return true;
704 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
705 *params = capabilities_.max_combined_texture_image_units;
706 return true;
707 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
708 *params = capabilities_.max_cube_map_texture_size;
709 return true;
710 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
711 *params = capabilities_.max_fragment_uniform_vectors;
712 return true;
713 case GL_MAX_RENDERBUFFER_SIZE:
714 *params = capabilities_.max_renderbuffer_size;
715 return true;
716 case GL_MAX_TEXTURE_IMAGE_UNITS:
717 *params = capabilities_.max_texture_image_units;
718 return true;
719 case GL_MAX_TEXTURE_SIZE:
720 *params = capabilities_.max_texture_size;
721 return true;
722 case GL_MAX_VARYING_VECTORS:
723 *params = capabilities_.max_varying_vectors;
724 return true;
725 case GL_MAX_VERTEX_ATTRIBS:
726 *params = capabilities_.max_vertex_attribs;
727 return true;
728 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
729 *params = capabilities_.max_vertex_texture_image_units;
730 return true;
731 case GL_MAX_VERTEX_UNIFORM_VECTORS:
732 *params = capabilities_.max_vertex_uniform_vectors;
733 return true;
734 case GL_MAX_VIEWPORT_DIMS:
735 if (capabilities_.max_viewport_width > 0 &&
736 capabilities_.max_viewport_height > 0) {
737 params[0] = capabilities_.max_viewport_width;
738 params[1] = capabilities_.max_viewport_height;
739 return true;
740 }
741 // If they are not cached on the client side yet, query the service side.
742 return false;
743 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
744 *params = capabilities_.num_compressed_texture_formats;
745 return true;
746 case GL_NUM_SHADER_BINARY_FORMATS:
747 *params = capabilities_.num_shader_binary_formats;
748 return true;
749 case GL_RENDERBUFFER_BINDING:
750 *params = bound_renderbuffer_;
751 return true;
752 case GL_TEXTURE_BINDING_2D:
753 *params = texture_units_[active_texture_unit_].bound_texture_2d;
754 return true;
755 case GL_TEXTURE_BINDING_CUBE_MAP:
756 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
757 return true;
758
759 // Non-standard parameters.
760 case GL_TEXTURE_BINDING_EXTERNAL_OES:
761 *params = texture_units_[active_texture_unit_].bound_texture_external_oes;
762 return true;
763 case GL_TEXTURE_BINDING_RECTANGLE_ARB:
764 *params =
765 texture_units_[active_texture_unit_].bound_texture_rectangle_arb;
766 return true;
767 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
768 *params = bound_pixel_pack_transfer_buffer_id_;
769 return true;
770 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
771 *params = bound_pixel_unpack_transfer_buffer_id_;
772 return true;
773 case GL_READ_FRAMEBUFFER_BINDING:
774 if (capabilities_.major_version >= 3 ||
775 IsChromiumFramebufferMultisampleAvailable()) {
776 *params = bound_read_framebuffer_;
777 return true;
778 }
779 break;
780 case GL_TIMESTAMP_EXT:
781 // We convert all GPU timestamps to CPU time.
782 *params = base::saturated_cast<GLint>(
783 (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds() *
784 base::Time::kNanosecondsPerMicrosecond);
785 return true;
786 case GL_GPU_DISJOINT_EXT:
787 *params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
788 return true;
789
790 case GL_VIEWPORT:
791 if (state_.viewport_width > 0 && state_.viewport_height > 0 &&
792 capabilities_.max_viewport_width > 0 &&
793 capabilities_.max_viewport_height > 0) {
794 params[0] = state_.viewport_x;
795 params[1] = state_.viewport_y;
796 params[2] =
797 std::min(state_.viewport_width, capabilities_.max_viewport_width);
798 params[3] =
799 std::min(state_.viewport_height, capabilities_.max_viewport_height);
800 return true;
801 }
802 // If they haven't been cached on the client side, go to service side
803 // to query the underlying driver.
804 return false;
805
806 // Non-cached parameters.
807 case GL_ALIASED_LINE_WIDTH_RANGE:
808 case GL_ALIASED_POINT_SIZE_RANGE:
809 case GL_ALPHA_BITS:
810 case GL_BLEND:
811 case GL_BLEND_COLOR:
812 case GL_BLEND_DST_ALPHA:
813 case GL_BLEND_DST_RGB:
814 case GL_BLEND_EQUATION_ALPHA:
815 case GL_BLEND_EQUATION_RGB:
816 case GL_BLEND_SRC_ALPHA:
817 case GL_BLEND_SRC_RGB:
818 case GL_BLUE_BITS:
819 case GL_COLOR_CLEAR_VALUE:
820 case GL_COLOR_WRITEMASK:
821 case GL_COMPRESSED_TEXTURE_FORMATS:
822 case GL_CULL_FACE:
823 case GL_CULL_FACE_MODE:
824 case GL_CURRENT_PROGRAM:
825 case GL_DEPTH_BITS:
826 case GL_DEPTH_CLEAR_VALUE:
827 case GL_DEPTH_FUNC:
828 case GL_DEPTH_RANGE:
829 case GL_DEPTH_TEST:
830 case GL_DEPTH_WRITEMASK:
831 case GL_DITHER:
832 case GL_FRONT_FACE:
833 case GL_GENERATE_MIPMAP_HINT:
834 case GL_GREEN_BITS:
835 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
836 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
837 case GL_LINE_WIDTH:
838 case GL_PACK_ALIGNMENT:
839 case GL_POLYGON_OFFSET_FACTOR:
840 case GL_POLYGON_OFFSET_FILL:
841 case GL_POLYGON_OFFSET_UNITS:
842 case GL_RED_BITS:
843 case GL_SAMPLE_ALPHA_TO_COVERAGE:
844 case GL_SAMPLE_BUFFERS:
845 case GL_SAMPLE_COVERAGE:
846 case GL_SAMPLE_COVERAGE_INVERT:
847 case GL_SAMPLE_COVERAGE_VALUE:
848 case GL_SAMPLES:
849 case GL_SCISSOR_BOX:
850 case GL_SCISSOR_TEST:
851 case GL_SHADER_BINARY_FORMATS:
852 case GL_SHADER_COMPILER:
853 case GL_STENCIL_BACK_FAIL:
854 case GL_STENCIL_BACK_FUNC:
855 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
856 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
857 case GL_STENCIL_BACK_REF:
858 case GL_STENCIL_BACK_VALUE_MASK:
859 case GL_STENCIL_BACK_WRITEMASK:
860 case GL_STENCIL_BITS:
861 case GL_STENCIL_CLEAR_VALUE:
862 case GL_STENCIL_FAIL:
863 case GL_STENCIL_FUNC:
864 case GL_STENCIL_PASS_DEPTH_FAIL:
865 case GL_STENCIL_PASS_DEPTH_PASS:
866 case GL_STENCIL_REF:
867 case GL_STENCIL_TEST:
868 case GL_STENCIL_VALUE_MASK:
869 case GL_STENCIL_WRITEMASK:
870 case GL_SUBPIXEL_BITS:
871 case GL_UNPACK_ALIGNMENT:
872 return false;
873 default:
874 break;
875 }
876
877 if (capabilities_.major_version < 3) {
878 return false;
879 }
880
881 // ES3 parameters.
882 switch (pname) {
883 case GL_COPY_READ_BUFFER_BINDING:
884 *params = bound_copy_read_buffer_;
885 return true;
886 case GL_COPY_WRITE_BUFFER_BINDING:
887 *params = bound_copy_write_buffer_;
888 return true;
889 case GL_MAJOR_VERSION:
890 *params = capabilities_.major_version;
891 return true;
892 case GL_MAX_3D_TEXTURE_SIZE:
893 *params = capabilities_.max_3d_texture_size;
894 return true;
895 case GL_MAX_ARRAY_TEXTURE_LAYERS:
896 *params = capabilities_.max_array_texture_layers;
897 return true;
898 case GL_MAX_COLOR_ATTACHMENTS:
899 *params = capabilities_.max_color_attachments;
900 return true;
901 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
902 *params = static_cast<GLint>(
903 capabilities_.max_combined_fragment_uniform_components);
904 return true;
905 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
906 *params = capabilities_.max_combined_uniform_blocks;
907 return true;
908 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
909 *params = static_cast<GLint>(
910 capabilities_.max_combined_vertex_uniform_components);
911 return true;
912 case GL_MAX_DRAW_BUFFERS:
913 *params = capabilities_.max_draw_buffers;
914 return true;
915 case GL_MAX_ELEMENT_INDEX:
916 *params = static_cast<GLint>(capabilities_.max_element_index);
917 return true;
918 case GL_MAX_ELEMENTS_INDICES:
919 *params = capabilities_.max_elements_indices;
920 return true;
921 case GL_MAX_ELEMENTS_VERTICES:
922 *params = capabilities_.max_elements_vertices;
923 return true;
924 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
925 *params = capabilities_.max_fragment_input_components;
926 return true;
927 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
928 *params = capabilities_.max_fragment_uniform_blocks;
929 return true;
930 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
931 *params = capabilities_.max_fragment_uniform_components;
932 return true;
933 case GL_MAX_PROGRAM_TEXEL_OFFSET:
934 *params = capabilities_.max_program_texel_offset;
935 return true;
936 case GL_MAX_SAMPLES:
937 *params = capabilities_.max_samples;
938 return true;
939 case GL_MAX_SERVER_WAIT_TIMEOUT:
940 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
941 return true;
942 case GL_MAX_TEXTURE_LOD_BIAS:
943 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
944 return true;
945 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
946 *params = capabilities_.max_transform_feedback_interleaved_components;
947 return true;
948 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
949 *params = capabilities_.max_transform_feedback_separate_attribs;
950 return true;
951 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
952 *params = capabilities_.max_transform_feedback_separate_components;
953 return true;
954 case GL_MAX_UNIFORM_BLOCK_SIZE:
955 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
956 return true;
957 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
958 *params = capabilities_.max_uniform_buffer_bindings;
959 return true;
960 case GL_MAX_VARYING_COMPONENTS:
961 *params = capabilities_.max_varying_components;
962 return true;
963 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
964 *params = capabilities_.max_vertex_output_components;
965 return true;
966 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
967 *params = capabilities_.max_vertex_uniform_blocks;
968 return true;
969 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
970 *params = capabilities_.max_vertex_uniform_components;
971 return true;
972 case GL_MIN_PROGRAM_TEXEL_OFFSET:
973 *params = capabilities_.min_program_texel_offset;
974 return true;
975 case GL_MINOR_VERSION:
976 *params = capabilities_.minor_version;
977 return true;
978 case GL_NUM_EXTENSIONS:
979 UpdateCachedExtensionsIfNeeded();
980 *params = cached_extensions_.size();
981 return true;
982 case GL_NUM_PROGRAM_BINARY_FORMATS:
983 *params = capabilities_.num_program_binary_formats;
984 return true;
985 case GL_PACK_SKIP_PIXELS:
986 *params = pack_skip_pixels_;
987 return true;
988 case GL_PACK_SKIP_ROWS:
989 *params = pack_skip_rows_;
990 return true;
991 case GL_PIXEL_PACK_BUFFER_BINDING:
992 *params = bound_pixel_pack_buffer_;
993 return true;
994 case GL_PIXEL_UNPACK_BUFFER_BINDING:
995 *params = bound_pixel_unpack_buffer_;
996 return true;
997 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
998 *params = bound_transform_feedback_buffer_;
999 return true;
1000 case GL_UNIFORM_BUFFER_BINDING:
1001 *params = bound_uniform_buffer_;
1002 return true;
1003 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
1004 *params = capabilities_.uniform_buffer_offset_alignment;
1005 return true;
1006 case GL_UNPACK_SKIP_IMAGES:
1007 *params = unpack_skip_images_;
1008 return true;
1009 case GL_UNPACK_SKIP_PIXELS:
1010 *params = unpack_skip_pixels_;
1011 return true;
1012 case GL_UNPACK_SKIP_ROWS:
1013 *params = unpack_skip_rows_;
1014 return true;
1015
1016 // Non-cached ES3 parameters.
1017 case GL_DRAW_BUFFER0:
1018 case GL_DRAW_BUFFER1:
1019 case GL_DRAW_BUFFER2:
1020 case GL_DRAW_BUFFER3:
1021 case GL_DRAW_BUFFER4:
1022 case GL_DRAW_BUFFER5:
1023 case GL_DRAW_BUFFER6:
1024 case GL_DRAW_BUFFER7:
1025 case GL_DRAW_BUFFER8:
1026 case GL_DRAW_BUFFER9:
1027 case GL_DRAW_BUFFER10:
1028 case GL_DRAW_BUFFER11:
1029 case GL_DRAW_BUFFER12:
1030 case GL_DRAW_BUFFER13:
1031 case GL_DRAW_BUFFER14:
1032 case GL_DRAW_BUFFER15:
1033 case GL_DRAW_FRAMEBUFFER_BINDING:
1034 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
1035 case GL_PACK_ROW_LENGTH:
1036 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
1037 case GL_PROGRAM_BINARY_FORMATS:
1038 case GL_RASTERIZER_DISCARD:
1039 case GL_READ_BUFFER:
1040 case GL_READ_FRAMEBUFFER_BINDING:
1041 case GL_SAMPLER_BINDING:
1042 case GL_TEXTURE_BINDING_2D_ARRAY:
1043 case GL_TEXTURE_BINDING_3D:
1044 case GL_TRANSFORM_FEEDBACK_BINDING:
1045 case GL_TRANSFORM_FEEDBACK_ACTIVE:
1046 case GL_TRANSFORM_FEEDBACK_PAUSED:
1047 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
1048 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
1049 case GL_UNIFORM_BUFFER_SIZE:
1050 case GL_UNIFORM_BUFFER_START:
1051 case GL_UNPACK_IMAGE_HEIGHT:
1052 case GL_UNPACK_ROW_LENGTH:
1053 case GL_VERTEX_ARRAY_BINDING:
1054 return false;
1055 default:
1056 break;
1057 }
1058
1059 if (capabilities_.minor_version < 1) {
1060 return false;
1061 }
1062
1063 // ES31 parameters.
1064 switch (pname) {
1065 case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
1066 *params = capabilities_.max_atomic_counter_buffer_bindings;
1067 return true;
1068 case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS:
1069 *params = capabilities_.max_shader_storage_buffer_bindings;
1070 return true;
1071 case GL_ATOMIC_COUNTER_BUFFER_BINDING:
1072 *params = bound_atomic_counter_buffer_;
1073 return true;
1074 case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
1075 *params = bound_dispatch_indirect_buffer_;
1076 return true;
1077 case GL_DRAW_INDIRECT_BUFFER_BINDING:
1078 *params = bound_draw_indirect_buffer_;
1079 return true;
1080 case GL_SHADER_STORAGE_BUFFER_BINDING:
1081 *params = bound_shader_storage_buffer_;
1082 return true;
1083 case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
1084 *params = capabilities_.shader_storage_buffer_offset_alignment;
1085 return true;
1086
1087 // Non-cached ES31 parameters.
1088 case GL_ATOMIC_COUNTER_BUFFER_SIZE:
1089 case GL_ATOMIC_COUNTER_BUFFER_START:
1090 case GL_SHADER_STORAGE_BUFFER_SIZE:
1091 case GL_SHADER_STORAGE_BUFFER_START:
1092 return false;
1093 default:
1094 return false;
1095 }
1096 }
1097
GetBooleanvHelper(GLenum pname,GLboolean * params)1098 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
1099 // TODO(gman): Make this handle pnames that return more than 1 value.
1100 GLint value;
1101 if (!GetHelper(pname, &value)) {
1102 return false;
1103 }
1104 *params = static_cast<GLboolean>(value);
1105 return true;
1106 }
1107
GetFloatvHelper(GLenum pname,GLfloat * params)1108 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
1109 // TODO(gman): Make this handle pnames that return more than 1 value.
1110 switch (pname) {
1111 case GL_MAX_TEXTURE_LOD_BIAS:
1112 *params = capabilities_.max_texture_lod_bias;
1113 return true;
1114 default:
1115 break;
1116 }
1117 GLint value;
1118 if (!GetHelper(pname, &value)) {
1119 return false;
1120 }
1121 *params = static_cast<GLfloat>(value);
1122 return true;
1123 }
1124
GetInteger64vHelper(GLenum pname,GLint64 * params)1125 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
1126 switch (pname) {
1127 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
1128 *params = capabilities_.max_combined_fragment_uniform_components;
1129 return true;
1130 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
1131 *params = capabilities_.max_combined_vertex_uniform_components;
1132 return true;
1133 case GL_MAX_ELEMENT_INDEX:
1134 *params = capabilities_.max_element_index;
1135 return true;
1136 case GL_MAX_SERVER_WAIT_TIMEOUT:
1137 *params = capabilities_.max_server_wait_timeout;
1138 return true;
1139 case GL_MAX_UNIFORM_BLOCK_SIZE:
1140 *params = capabilities_.max_uniform_block_size;
1141 return true;
1142 case GL_TIMESTAMP_EXT:
1143 // We convert all GPU timestamps to CPU time.
1144 *params = (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds() *
1145 base::Time::kNanosecondsPerMicrosecond;
1146 return true;
1147 default:
1148 break;
1149 }
1150 GLint value;
1151 if (!GetHelper(pname, &value)) {
1152 return false;
1153 }
1154 *params = static_cast<GLint64>(value);
1155 return true;
1156 }
1157
GetIntegervHelper(GLenum pname,GLint * params)1158 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1159 return GetHelper(pname, params);
1160 }
1161
GetIntegeri_vHelper(GLenum pname,GLuint index,GLint * data)1162 bool GLES2Implementation::GetIntegeri_vHelper(GLenum pname,
1163 GLuint index,
1164 GLint* data) {
1165 // TODO(zmo): Implement client side caching.
1166 return false;
1167 }
1168
GetInteger64i_vHelper(GLenum pname,GLuint index,GLint64 * data)1169 bool GLES2Implementation::GetInteger64i_vHelper(GLenum pname,
1170 GLuint index,
1171 GLint64* data) {
1172 // TODO(zmo): Implement client side caching.
1173 return false;
1174 }
1175
GetInternalformativHelper(GLenum target,GLenum format,GLenum pname,GLsizei bufSize,GLint * params)1176 bool GLES2Implementation::GetInternalformativHelper(GLenum target,
1177 GLenum format,
1178 GLenum pname,
1179 GLsizei bufSize,
1180 GLint* params) {
1181 // TODO(zmo): Implement the client side caching.
1182 return false;
1183 }
1184
GetSyncivHelper(GLsync sync,GLenum pname,GLsizei bufsize,GLsizei * length,GLint * values)1185 bool GLES2Implementation::GetSyncivHelper(GLsync sync,
1186 GLenum pname,
1187 GLsizei bufsize,
1188 GLsizei* length,
1189 GLint* values) {
1190 GLint value = 0;
1191 switch (pname) {
1192 case GL_OBJECT_TYPE:
1193 value = GL_SYNC_FENCE;
1194 break;
1195 case GL_SYNC_CONDITION:
1196 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1197 break;
1198 case GL_SYNC_FLAGS:
1199 value = 0;
1200 break;
1201 default:
1202 return false;
1203 }
1204 if (bufsize > 0) {
1205 DCHECK(values);
1206 *values = value;
1207 }
1208 if (length) {
1209 *length = 1;
1210 }
1211 return true;
1212 }
1213
GetQueryObjectValueHelper(const char * function_name,GLuint id,GLenum pname,GLuint64 * params)1214 bool GLES2Implementation::GetQueryObjectValueHelper(const char* function_name,
1215 GLuint id,
1216 GLenum pname,
1217 GLuint64* params) {
1218 GPU_CLIENT_SINGLE_THREAD_CHECK();
1219 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryObjectValueHelper(" << id
1220 << ", " << GLES2Util::GetStringQueryObjectParameter(pname)
1221 << ", " << static_cast<const void*>(params) << ")");
1222
1223 QueryTracker::Query* query = query_tracker_->GetQuery(id);
1224 if (!query) {
1225 SetGLError(GL_INVALID_OPERATION, function_name, "unknown query id");
1226 return false;
1227 }
1228
1229 if (query->Active()) {
1230 SetGLError(GL_INVALID_OPERATION, function_name,
1231 "query active. Did you call glEndQueryEXT?");
1232 return false;
1233 }
1234
1235 if (query->NeverUsed()) {
1236 SetGLError(GL_INVALID_OPERATION, function_name,
1237 "Never used. Did you call glBeginQueryEXT?");
1238 return false;
1239 }
1240
1241 bool valid_value = false;
1242 const bool flush_if_pending =
1243 pname != GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT;
1244 switch (pname) {
1245 case GL_QUERY_RESULT_EXT:
1246 if (!query->CheckResultsAvailable(helper_, flush_if_pending)) {
1247 helper_->WaitForToken(query->token());
1248 if (!query->CheckResultsAvailable(helper_, flush_if_pending)) {
1249 FinishHelper();
1250 CHECK(query->CheckResultsAvailable(helper_, flush_if_pending));
1251 }
1252 }
1253 *params = query->GetResult();
1254 valid_value = true;
1255 break;
1256 case GL_QUERY_RESULT_AVAILABLE_EXT:
1257 *params = query->CheckResultsAvailable(helper_, flush_if_pending);
1258 valid_value = true;
1259 break;
1260 case GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT:
1261 *params = query->CheckResultsAvailable(helper_, flush_if_pending);
1262 valid_value = true;
1263 break;
1264 default:
1265 SetGLErrorInvalidEnum(function_name, pname, "pname");
1266 break;
1267 }
1268 GPU_CLIENT_LOG(" " << *params);
1269 CheckGLError();
1270 return valid_value;
1271 }
1272
GetMaxValueInBufferCHROMIUMHelper(GLuint buffer_id,GLsizei count,GLenum type,GLuint offset)1273 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(GLuint buffer_id,
1274 GLsizei count,
1275 GLenum type,
1276 GLuint offset) {
1277 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1278 auto result = GetResultAs<Result>();
1279 if (!result) {
1280 return 0;
1281 }
1282 *result = 0;
1283 helper_->GetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset,
1284 GetResultShmId(), result.offset());
1285 WaitForCmd();
1286 return *result;
1287 }
1288
GetMaxValueInBufferCHROMIUM(GLuint buffer_id,GLsizei count,GLenum type,GLuint offset)1289 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(GLuint buffer_id,
1290 GLsizei count,
1291 GLenum type,
1292 GLuint offset) {
1293 GPU_CLIENT_SINGLE_THREAD_CHECK();
1294 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1295 << buffer_id << ", " << count << ", "
1296 << GLES2Util::GetStringGetMaxIndexType(type) << ", "
1297 << offset << ")");
1298 GLuint result =
1299 GetMaxValueInBufferCHROMIUMHelper(buffer_id, count, type, offset);
1300 GPU_CLIENT_LOG("returned " << result);
1301 CheckGLError();
1302 return result;
1303 }
1304
RestoreElementAndArrayBuffers(bool restore)1305 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1306 if (restore) {
1307 RestoreArrayBuffer(restore);
1308 // Restore the element array binding.
1309 // We only need to restore it if it wasn't a client side array.
1310 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1311 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1312 }
1313 }
1314 }
1315
RestoreArrayBuffer(bool restore)1316 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1317 if (restore) {
1318 // Restore the user's current binding.
1319 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1320 }
1321 }
1322
DrawElements(GLenum mode,GLsizei count,GLenum type,const void * indices)1323 void GLES2Implementation::DrawElements(GLenum mode,
1324 GLsizei count,
1325 GLenum type,
1326 const void* indices) {
1327 GPU_CLIENT_SINGLE_THREAD_CHECK();
1328 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1329 << GLES2Util::GetStringDrawMode(mode) << ", " << count
1330 << ", " << GLES2Util::GetStringIndexType(type) << ", "
1331 << static_cast<const void*>(indices) << ")");
1332 DrawElementsImpl(mode, count, type, indices, "glDrawElements");
1333 }
1334
DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const void * indices)1335 void GLES2Implementation::DrawRangeElements(GLenum mode,
1336 GLuint start,
1337 GLuint end,
1338 GLsizei count,
1339 GLenum type,
1340 const void* indices) {
1341 GPU_CLIENT_SINGLE_THREAD_CHECK();
1342 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1343 << GLES2Util::GetStringDrawMode(mode) << ", " << start
1344 << ", " << end << ", " << count << ", "
1345 << GLES2Util::GetStringIndexType(type) << ", "
1346 << static_cast<const void*>(indices) << ")");
1347 if (end < start) {
1348 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1349 return;
1350 }
1351 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1352 }
1353
DrawElementsImpl(GLenum mode,GLsizei count,GLenum type,const void * indices,const char * func_name)1354 void GLES2Implementation::DrawElementsImpl(GLenum mode,
1355 GLsizei count,
1356 GLenum type,
1357 const void* indices,
1358 const char* func_name) {
1359 if (count < 0) {
1360 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1361 return;
1362 }
1363 bool simulated = false;
1364 GLuint offset = ToGLuint(indices);
1365 if (count > 0) {
1366 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1367 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1368 return;
1369 }
1370 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1371 func_name, this, helper_, count, type, 0, indices, &offset,
1372 &simulated)) {
1373 return;
1374 }
1375 }
1376 helper_->DrawElements(mode, count, type, offset);
1377 RestoreElementAndArrayBuffers(simulated);
1378 CheckGLError();
1379 }
1380
DrawElementsIndirect(GLenum mode,GLenum type,const void * offset)1381 void GLES2Implementation::DrawElementsIndirect(GLenum mode,
1382 GLenum type,
1383 const void* offset) {
1384 GPU_CLIENT_SINGLE_THREAD_CHECK();
1385 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsIndirect("
1386 << GLES2Util::GetStringDrawMode(mode) << ", "
1387 << GLES2Util::GetStringIndexType(type) << ", " << offset
1388 << ")");
1389 if (!ValidateOffset("glDrawElementsIndirect",
1390 reinterpret_cast<GLintptr>(offset))) {
1391 return;
1392 }
1393 // This is for WebGL 2.0 Compute which doesn't support client side arrays
1394 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1395 SetGLError(GL_INVALID_OPERATION, "glDrawElementsIndirect",
1396 "No element array buffer");
1397 return;
1398 }
1399 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
1400 SetGLError(GL_INVALID_OPERATION, "glDrawElementsIndirect",
1401 "Missing array buffer for vertex attribute");
1402 return;
1403 }
1404 helper_->DrawElementsIndirect(mode, type, ToGLuint(offset));
1405 CheckGLError();
1406 }
1407
Flush()1408 void GLES2Implementation::Flush() {
1409 GPU_CLIENT_SINGLE_THREAD_CHECK();
1410 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1411 flush_id_ = GenerateNextFlushId();
1412 // Insert the cmd to call glFlush
1413 helper_->Flush();
1414 FlushHelper();
1415 }
1416
1417 // InterfaceBase implementation.
GenSyncTokenCHROMIUM(GLbyte * sync_token)1418 void GLES2Implementation::GenSyncTokenCHROMIUM(GLbyte* sync_token) {
1419 ImplementationBase::GenSyncToken(sync_token);
1420 }
GenUnverifiedSyncTokenCHROMIUM(GLbyte * sync_token)1421 void GLES2Implementation::GenUnverifiedSyncTokenCHROMIUM(GLbyte* sync_token) {
1422 ImplementationBase::GenUnverifiedSyncToken(sync_token);
1423 }
VerifySyncTokensCHROMIUM(GLbyte ** sync_tokens,GLsizei count)1424 void GLES2Implementation::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens,
1425 GLsizei count) {
1426 ImplementationBase::VerifySyncTokens(sync_tokens, count);
1427 }
WaitSyncTokenCHROMIUM(const GLbyte * sync_token)1428 void GLES2Implementation::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
1429 ImplementationBase::WaitSyncToken(sync_token);
1430 }
1431
1432 // ImplementationBase implementation.
IssueShallowFlush()1433 void GLES2Implementation::IssueShallowFlush() {
1434 GPU_CLIENT_SINGLE_THREAD_CHECK();
1435 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1436 flush_id_ = GenerateNextFlushId();
1437 FlushHelper();
1438 }
1439
ShallowFlushCHROMIUM()1440 void GLES2Implementation::ShallowFlushCHROMIUM() {
1441 IssueShallowFlush();
1442 }
1443
FlushHelper()1444 void GLES2Implementation::FlushHelper() {
1445 // Flush our command buffer
1446 // (tell the service to execute up to the flush cmd.)
1447 helper_->CommandBufferHelper::Flush();
1448
1449 if (aggressively_free_resources_)
1450 FreeEverything();
1451 }
1452
OrderingBarrierCHROMIUM()1453 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1454 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1455 // Flush command buffer at the GPU channel level. May be implemented as
1456 // Flush().
1457 helper_->CommandBufferHelper::OrderingBarrier();
1458 }
1459
Finish()1460 void GLES2Implementation::Finish() {
1461 GPU_CLIENT_SINGLE_THREAD_CHECK();
1462 flush_id_ = GenerateNextFlushId();
1463 FinishHelper();
1464 }
1465
ShallowFinishCHROMIUM()1466 void GLES2Implementation::ShallowFinishCHROMIUM() {
1467 GPU_CLIENT_SINGLE_THREAD_CHECK();
1468 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1469 flush_id_ = GenerateNextFlushId();
1470 // Flush our command buffer (tell the service to execute up to the flush cmd
1471 // and don't return until it completes).
1472 helper_->CommandBufferHelper::Finish();
1473
1474 if (aggressively_free_resources_)
1475 FreeEverything();
1476 }
1477
FinishHelper()1478 void GLES2Implementation::FinishHelper() {
1479 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1480 TRACE_EVENT0("gpu", "GLES2::Finish");
1481 // Insert the cmd to call glFinish
1482 helper_->Finish();
1483 // Finish our command buffer
1484 // (tell the service to execute up to the Finish cmd and wait for it to
1485 // execute.)
1486 helper_->CommandBufferHelper::Finish();
1487
1488 if (aggressively_free_resources_)
1489 FreeEverything();
1490 }
1491
GetLastFlushIdCHROMIUM()1492 GLuint GLES2Implementation::GetLastFlushIdCHROMIUM() {
1493 GPU_CLIENT_SINGLE_THREAD_CHECK();
1494 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetLastFlushIdCHROMIUM()");
1495 return flush_id_;
1496 }
1497
SwapBuffers(uint64_t swap_id,GLbitfield flags)1498 void GLES2Implementation::SwapBuffers(uint64_t swap_id, GLbitfield flags) {
1499 GPU_CLIENT_SINGLE_THREAD_CHECK();
1500 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1501 // TODO(piman): Strictly speaking we'd want to insert the token after the
1502 // swap, but the state update with the updated token might not have happened
1503 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1504 // with the GPU process more than needed. So instead, make it happen before.
1505 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1506 // semantics if the client doesn't use the callback mechanism, and by chance
1507 // the scheduler yields between the InsertToken and the SwapBuffers.
1508 swap_buffers_tokens_.push(helper_->InsertToken());
1509 helper_->SwapBuffers(swap_id, flags);
1510 helper_->CommandBufferHelper::Flush();
1511 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1512 // compensate for TODO above.
1513 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1514 helper_->WaitForToken(swap_buffers_tokens_.front());
1515 swap_buffers_tokens_.pop();
1516 }
1517 }
1518
SwapBuffersWithBoundsCHROMIUM(uint64_t swap_id,GLsizei count,const GLint * rects,GLbitfield flags)1519 void GLES2Implementation::SwapBuffersWithBoundsCHROMIUM(uint64_t swap_id,
1520 GLsizei count,
1521 const GLint* rects,
1522 GLbitfield flags) {
1523 GPU_CLIENT_SINGLE_THREAD_CHECK();
1524 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffersWithBoundsCHROMIUM("
1525 << count << ", " << static_cast<const void*>(rects)
1526 << ")");
1527 GPU_CLIENT_LOG_CODE_BLOCK({
1528 for (GLsizei i = 0; i < count; ++i) {
1529 GPU_CLIENT_LOG(" " << i << ": " << rects[0 + i * 4] << ", "
1530 << rects[1 + i * 4] << ", " << rects[2 + i * 4]
1531 << ", " << rects[3 + i * 4]);
1532 }
1533 });
1534 if (count < 0) {
1535 SetGLError(GL_INVALID_VALUE, "glSwapBuffersWithBoundsCHROMIUM",
1536 "count < 0");
1537 return;
1538 }
1539
1540 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
1541 swap_buffers_tokens_.push(helper_->InsertToken());
1542 helper_->SwapBuffersWithBoundsCHROMIUMImmediate(swap_id, count, rects, flags);
1543 helper_->CommandBufferHelper::Flush();
1544 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1545 helper_->WaitForToken(swap_buffers_tokens_.front());
1546 swap_buffers_tokens_.pop();
1547 }
1548 }
1549
BindAttribLocation(GLuint program,GLuint index,const char * name)1550 void GLES2Implementation::BindAttribLocation(GLuint program,
1551 GLuint index,
1552 const char* name) {
1553 GPU_CLIENT_SINGLE_THREAD_CHECK();
1554 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation(" << program
1555 << ", " << index << ", " << name << ")");
1556 SetBucketAsString(kResultBucketId, name);
1557 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1558 helper_->SetBucketSize(kResultBucketId, 0);
1559 CheckGLError();
1560 }
1561
BindFragDataLocationEXT(GLuint program,GLuint colorName,const char * name)1562 void GLES2Implementation::BindFragDataLocationEXT(GLuint program,
1563 GLuint colorName,
1564 const char* name) {
1565 GPU_CLIENT_SINGLE_THREAD_CHECK();
1566 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT("
1567 << program << ", " << colorName << ", " << name << ")");
1568 SetBucketAsString(kResultBucketId, name);
1569 helper_->BindFragDataLocationEXTBucket(program, colorName, kResultBucketId);
1570 helper_->SetBucketSize(kResultBucketId, 0);
1571 CheckGLError();
1572 }
1573
BindFragDataLocationIndexedEXT(GLuint program,GLuint colorName,GLuint index,const char * name)1574 void GLES2Implementation::BindFragDataLocationIndexedEXT(GLuint program,
1575 GLuint colorName,
1576 GLuint index,
1577 const char* name) {
1578 GPU_CLIENT_SINGLE_THREAD_CHECK();
1579 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT("
1580 << program << ", " << colorName << ", " << index << ", "
1581 << name << ")");
1582 SetBucketAsString(kResultBucketId, name);
1583 helper_->BindFragDataLocationIndexedEXTBucket(program, colorName, index,
1584 kResultBucketId);
1585 helper_->SetBucketSize(kResultBucketId, 0);
1586 CheckGLError();
1587 }
1588
BindUniformLocationCHROMIUM(GLuint program,GLint location,const char * name)1589 void GLES2Implementation::BindUniformLocationCHROMIUM(GLuint program,
1590 GLint location,
1591 const char* name) {
1592 GPU_CLIENT_SINGLE_THREAD_CHECK();
1593 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1594 << program << ", " << location << ", " << name << ")");
1595 SetBucketAsString(kResultBucketId, name);
1596 helper_->BindUniformLocationCHROMIUMBucket(program, location,
1597 kResultBucketId);
1598 helper_->SetBucketSize(kResultBucketId, 0);
1599 CheckGLError();
1600 }
1601
GetVertexAttribPointerv(GLuint index,GLenum pname,void ** ptr)1602 void GLES2Implementation::GetVertexAttribPointerv(GLuint index,
1603 GLenum pname,
1604 void** ptr) {
1605 GPU_CLIENT_SINGLE_THREAD_CHECK();
1606 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer(" << index
1607 << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1608 << static_cast<void*>(ptr) << ")");
1609 GPU_CLIENT_LOG_CODE_BLOCK(int32_t num_results = 1);
1610 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1611 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1612 typedef cmds::GetVertexAttribPointerv::Result Result;
1613 auto result = GetResultAs<Result>();
1614 if (!result) {
1615 return;
1616 }
1617 result->SetNumResults(0);
1618 helper_->GetVertexAttribPointerv(index, pname, GetResultShmId(),
1619 result.offset());
1620 WaitForCmd();
1621 result->CopyResult(ptr);
1622 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1623 }
1624 GPU_CLIENT_LOG_CODE_BLOCK({
1625 for (int32_t i = 0; i < num_results; ++i) {
1626 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1627 }
1628 });
1629 CheckGLError();
1630 }
1631
DeleteProgramHelper(GLuint program)1632 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1633 if (!GetIdHandler(SharedIdNamespaces::kProgramsAndShaders)
1634 ->FreeIds(this, 1, &program,
1635 &GLES2Implementation::DeleteProgramStub)) {
1636 SetGLError(GL_INVALID_VALUE, "glDeleteProgram",
1637 "id not created by this context.");
1638 return false;
1639 }
1640 if (program == current_program_) {
1641 current_program_ = 0;
1642 }
1643 return true;
1644 }
1645
DeleteProgramStub(GLsizei n,const GLuint * programs)1646 void GLES2Implementation::DeleteProgramStub(GLsizei n, const GLuint* programs) {
1647 DCHECK_EQ(1, n);
1648 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1649 helper_->DeleteProgram(programs[0]);
1650 }
1651
DeleteShaderHelper(GLuint shader)1652 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1653 if (!GetIdHandler(SharedIdNamespaces::kProgramsAndShaders)
1654 ->FreeIds(this, 1, &shader,
1655 &GLES2Implementation::DeleteShaderStub)) {
1656 SetGLError(GL_INVALID_VALUE, "glDeleteShader",
1657 "id not created by this context.");
1658 return false;
1659 }
1660 return true;
1661 }
1662
DeleteShaderStub(GLsizei n,const GLuint * shaders)1663 void GLES2Implementation::DeleteShaderStub(GLsizei n, const GLuint* shaders) {
1664 DCHECK_EQ(1, n);
1665 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1666 helper_->DeleteShader(shaders[0]);
1667 }
1668
DeleteSyncHelper(GLsync sync)1669 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1670 GLuint sync_uint = ToGLuint(sync);
1671 if (!GetIdHandler(SharedIdNamespaces::kSyncs)
1672 ->FreeIds(this, 1, &sync_uint,
1673 &GLES2Implementation::DeleteSyncStub)) {
1674 SetGLError(GL_INVALID_VALUE, "glDeleteSync",
1675 "id not created by this context.");
1676 }
1677 }
1678
DeleteSyncStub(GLsizei n,const GLuint * syncs)1679 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1680 DCHECK_EQ(1, n);
1681 helper_->DeleteSync(syncs[0]);
1682 }
1683
GetAttribLocationHelper(GLuint program,const char * name)1684 GLint GLES2Implementation::GetAttribLocationHelper(GLuint program,
1685 const char* name) {
1686 typedef cmds::GetAttribLocation::Result Result;
1687 SetBucketAsCString(kResultBucketId, name);
1688 auto result = GetResultAs<Result>();
1689 if (!result) {
1690 return -1;
1691 }
1692 *result = -1;
1693 helper_->GetAttribLocation(program, kResultBucketId, GetResultShmId(),
1694 result.offset());
1695 WaitForCmd();
1696 helper_->SetBucketSize(kResultBucketId, 0);
1697 return *result;
1698 }
1699
GetAttribLocation(GLuint program,const char * name)1700 GLint GLES2Implementation::GetAttribLocation(GLuint program, const char* name) {
1701 GPU_CLIENT_SINGLE_THREAD_CHECK();
1702 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1703 << ", " << name << ")");
1704 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1705 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1706 this, program, name);
1707 GPU_CLIENT_LOG("returned " << loc);
1708 CheckGLError();
1709 return loc;
1710 }
1711
GetUniformLocationHelper(GLuint program,const char * name)1712 GLint GLES2Implementation::GetUniformLocationHelper(GLuint program,
1713 const char* name) {
1714 typedef cmds::GetUniformLocation::Result Result;
1715 SetBucketAsCString(kResultBucketId, name);
1716 auto result = GetResultAs<Result>();
1717 if (!result) {
1718 return -1;
1719 }
1720 *result = -1;
1721 helper_->GetUniformLocation(program, kResultBucketId, GetResultShmId(),
1722 result.offset());
1723 WaitForCmd();
1724 helper_->SetBucketSize(kResultBucketId, 0);
1725 return *result;
1726 }
1727
GetUniformLocation(GLuint program,const char * name)1728 GLint GLES2Implementation::GetUniformLocation(GLuint program,
1729 const char* name) {
1730 GPU_CLIENT_SINGLE_THREAD_CHECK();
1731 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1732 << ", " << name << ")");
1733 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1734 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1735 this, program, name);
1736 GPU_CLIENT_LOG("returned " << loc);
1737 CheckGLError();
1738 return loc;
1739 }
1740
GetUniformIndicesHelper(GLuint program,GLsizei count,const char * const * names,GLuint * indices)1741 bool GLES2Implementation::GetUniformIndicesHelper(GLuint program,
1742 GLsizei count,
1743 const char* const* names,
1744 GLuint* indices) {
1745 if (!PackStringsToBucket(count, names, nullptr, "glGetUniformIndices")) {
1746 return false;
1747 }
1748 typedef cmds::GetUniformIndices::Result Result;
1749 auto result = GetResultAs<Result>();
1750 if (!result) {
1751 return false;
1752 }
1753 result->SetNumResults(0);
1754 helper_->GetUniformIndices(program, kResultBucketId, GetResultShmId(),
1755 result.offset());
1756 WaitForCmd();
1757 if (result->GetNumResults() != count) {
1758 return false;
1759 }
1760 result->CopyResult(indices);
1761 return true;
1762 }
1763
GetUniformIndices(GLuint program,GLsizei count,const char * const * names,GLuint * indices)1764 void GLES2Implementation::GetUniformIndices(GLuint program,
1765 GLsizei count,
1766 const char* const* names,
1767 GLuint* indices) {
1768 GPU_CLIENT_SINGLE_THREAD_CHECK();
1769 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1770 << ", " << count << ", " << names << ", " << indices
1771 << ")");
1772 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1773 if (count < 0) {
1774 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1775 return;
1776 }
1777 if (count == 0) {
1778 return;
1779 }
1780 bool success = share_group_->program_info_manager()->GetUniformIndices(
1781 this, program, count, names, indices);
1782 if (success) {
1783 GPU_CLIENT_LOG_CODE_BLOCK({
1784 for (GLsizei ii = 0; ii < count; ++ii) {
1785 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1786 }
1787 });
1788 }
1789 CheckGLError();
1790 }
1791
GetProgramivHelper(GLuint program,GLenum pname,GLint * params)1792 bool GLES2Implementation::GetProgramivHelper(GLuint program,
1793 GLenum pname,
1794 GLint* params) {
1795 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1796 this, program, pname, params);
1797 GPU_CLIENT_LOG_CODE_BLOCK({
1798 if (got_value) {
1799 GPU_CLIENT_LOG(" 0: " << *params);
1800 }
1801 });
1802 return got_value;
1803 }
1804
GetFragDataIndexEXTHelper(GLuint program,const char * name)1805 GLint GLES2Implementation::GetFragDataIndexEXTHelper(GLuint program,
1806 const char* name) {
1807 typedef cmds::GetFragDataIndexEXT::Result Result;
1808 SetBucketAsCString(kResultBucketId, name);
1809 auto result = GetResultAs<Result>();
1810 if (!result) {
1811 return -1;
1812 }
1813 *result = -1;
1814 helper_->GetFragDataIndexEXT(program, kResultBucketId, GetResultShmId(),
1815 result.offset());
1816 WaitForCmd();
1817 helper_->SetBucketSize(kResultBucketId, 0);
1818 return *result;
1819 }
1820
GetFragDataIndexEXT(GLuint program,const char * name)1821 GLint GLES2Implementation::GetFragDataIndexEXT(GLuint program,
1822 const char* name) {
1823 GPU_CLIENT_SINGLE_THREAD_CHECK();
1824 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataIndexEXT(" << program
1825 << ", " << name << ")");
1826 TRACE_EVENT0("gpu", "GLES2::GetFragDataIndexEXT");
1827 GLint loc = share_group_->program_info_manager()->GetFragDataIndex(
1828 this, program, name);
1829 GPU_CLIENT_LOG("returned " << loc);
1830 CheckGLError();
1831 return loc;
1832 }
1833
GetFragDataLocationHelper(GLuint program,const char * name)1834 GLint GLES2Implementation::GetFragDataLocationHelper(GLuint program,
1835 const char* name) {
1836 typedef cmds::GetFragDataLocation::Result Result;
1837 SetBucketAsCString(kResultBucketId, name);
1838 auto result = GetResultAs<Result>();
1839 if (!result) {
1840 return -1;
1841 }
1842 *result = -1;
1843 helper_->GetFragDataLocation(program, kResultBucketId, GetResultShmId(),
1844 result.offset());
1845 WaitForCmd();
1846 helper_->SetBucketSize(kResultBucketId, 0);
1847 return *result;
1848 }
1849
GetFragDataLocation(GLuint program,const char * name)1850 GLint GLES2Implementation::GetFragDataLocation(GLuint program,
1851 const char* name) {
1852 GPU_CLIENT_SINGLE_THREAD_CHECK();
1853 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation(" << program
1854 << ", " << name << ")");
1855 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1856 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1857 this, program, name);
1858 GPU_CLIENT_LOG("returned " << loc);
1859 CheckGLError();
1860 return loc;
1861 }
1862
GetUniformBlockIndexHelper(GLuint program,const char * name)1863 GLuint GLES2Implementation::GetUniformBlockIndexHelper(GLuint program,
1864 const char* name) {
1865 typedef cmds::GetUniformBlockIndex::Result Result;
1866 SetBucketAsCString(kResultBucketId, name);
1867 auto result = GetResultAs<Result>();
1868 if (!result) {
1869 return GL_INVALID_INDEX;
1870 }
1871 *result = GL_INVALID_INDEX;
1872 helper_->GetUniformBlockIndex(program, kResultBucketId, GetResultShmId(),
1873 result.offset());
1874 WaitForCmd();
1875 helper_->SetBucketSize(kResultBucketId, 0);
1876 return *result;
1877 }
1878
GetUniformBlockIndex(GLuint program,const char * name)1879 GLuint GLES2Implementation::GetUniformBlockIndex(GLuint program,
1880 const char* name) {
1881 GPU_CLIENT_SINGLE_THREAD_CHECK();
1882 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex(" << program
1883 << ", " << name << ")");
1884 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1885 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1886 this, program, name);
1887 GPU_CLIENT_LOG("returned " << index);
1888 CheckGLError();
1889 return index;
1890 }
1891
GetProgramInterfaceivHelper(GLuint program,GLenum program_interface,GLenum pname,GLint * params)1892 bool GLES2Implementation::GetProgramInterfaceivHelper(GLuint program,
1893 GLenum program_interface,
1894 GLenum pname,
1895 GLint* params) {
1896 bool success = share_group_->program_info_manager()->GetProgramInterfaceiv(
1897 this, program, program_interface, pname, params);
1898 GPU_CLIENT_LOG_CODE_BLOCK({
1899 if (success) {
1900 GPU_CLIENT_LOG(" 0: " << *params);
1901 }
1902 });
1903 return success;
1904 }
1905
GetProgramResourceIndexHelper(GLuint program,GLenum program_interface,const char * name)1906 GLuint GLES2Implementation::GetProgramResourceIndexHelper(
1907 GLuint program,
1908 GLenum program_interface,
1909 const char* name) {
1910 typedef cmds::GetProgramResourceIndex::Result Result;
1911 SetBucketAsCString(kResultBucketId, name);
1912 auto result = GetResultAs<Result>();
1913 if (!result) {
1914 return GL_INVALID_INDEX;
1915 }
1916 *result = GL_INVALID_INDEX;
1917 helper_->GetProgramResourceIndex(program, program_interface, kResultBucketId,
1918 GetResultShmId(), result.offset());
1919 WaitForCmd();
1920 helper_->SetBucketSize(kResultBucketId, 0);
1921 return *result;
1922 }
1923
GetProgramResourceIndex(GLuint program,GLenum program_interface,const char * name)1924 GLuint GLES2Implementation::GetProgramResourceIndex(
1925 GLuint program,
1926 GLenum program_interface,
1927 const char* name) {
1928 GPU_CLIENT_SINGLE_THREAD_CHECK();
1929 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetProgramResourceIndex("
1930 << program << ", " << program_interface << ", " << name
1931 << ")");
1932 TRACE_EVENT0("gpu", "GLES2::GetProgramResourceIndex");
1933 GLuint index = share_group_->program_info_manager()->GetProgramResourceIndex(
1934 this, program, program_interface, name);
1935 GPU_CLIENT_LOG("returned " << index);
1936 CheckGLError();
1937 return index;
1938 }
1939
GetProgramResourceNameHelper(GLuint program,GLenum program_interface,GLuint index,GLsizei bufsize,GLsizei * length,char * name)1940 bool GLES2Implementation::GetProgramResourceNameHelper(GLuint program,
1941 GLenum program_interface,
1942 GLuint index,
1943 GLsizei bufsize,
1944 GLsizei* length,
1945 char* name) {
1946 DCHECK_LE(0, bufsize);
1947 // Clear the bucket so if the command fails nothing will be in it.
1948 helper_->SetBucketSize(kResultBucketId, 0);
1949 bool success = false;
1950 {
1951 // The Result pointer must be scoped to this block because it can be
1952 // invalidated below if getting result name causes the transfer buffer to be
1953 // reallocated.
1954 typedef cmds::GetProgramResourceName::Result Result;
1955 auto result = GetResultAs<Result>();
1956 if (!result) {
1957 return false;
1958 }
1959 // Set as failed so if the command fails we'll recover.
1960 *result = 0;
1961 helper_->GetProgramResourceName(program, program_interface, index,
1962 kResultBucketId, GetResultShmId(),
1963 result.offset());
1964 WaitForCmd();
1965 success = !!*result;
1966 }
1967 if (success) {
1968 GetResultNameHelper(bufsize, length, name);
1969 }
1970 return success;
1971 }
1972
GetProgramResourceName(GLuint program,GLenum program_interface,GLuint index,GLsizei bufsize,GLsizei * length,char * name)1973 void GLES2Implementation::GetProgramResourceName(GLuint program,
1974 GLenum program_interface,
1975 GLuint index,
1976 GLsizei bufsize,
1977 GLsizei* length,
1978 char* name) {
1979 GPU_CLIENT_SINGLE_THREAD_CHECK();
1980 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetProgramResourceName("
1981 << program << ", " << program_interface << ", " << index
1982 << ", " << bufsize << ", " << static_cast<void*>(length)
1983 << ", " << static_cast<void*>(name) << ")");
1984 if (bufsize < 0) {
1985 SetGLError(GL_INVALID_VALUE, "glGetProgramResourceName", "bufsize < 0");
1986 return;
1987 }
1988 TRACE_EVENT0("gpu", "GLES2::GetProgramResourceName");
1989 bool success = share_group_->program_info_manager()->GetProgramResourceName(
1990 this, program, program_interface, index, bufsize, length, name);
1991 if (success && name) {
1992 GPU_CLIENT_LOG(" name: " << name);
1993 }
1994 CheckGLError();
1995 }
1996
GetProgramResourceivHelper(GLuint program,GLenum program_interface,GLuint index,GLsizei prop_count,const GLenum * props,GLsizei bufsize,GLsizei * length,GLint * params)1997 bool GLES2Implementation::GetProgramResourceivHelper(GLuint program,
1998 GLenum program_interface,
1999 GLuint index,
2000 GLsizei prop_count,
2001 const GLenum* props,
2002 GLsizei bufsize,
2003 GLsizei* length,
2004 GLint* params) {
2005 DCHECK_LE(0, prop_count);
2006 DCHECK_LE(0, bufsize);
2007 base::CheckedNumeric<uint32_t> bytes = prop_count;
2008 bytes *= sizeof(GLenum);
2009 if (!bytes.IsValid()) {
2010 SetGLError(GL_INVALID_VALUE, "glGetProgramResourceiv", "count overflow");
2011 return false;
2012 }
2013 SetBucketContents(kResultBucketId, props, bytes.ValueOrDefault(0));
2014 typedef cmds::GetProgramResourceiv::Result Result;
2015 auto result = GetResultAs<Result>();
2016 if (!result) {
2017 return false;
2018 }
2019 result->SetNumResults(0);
2020 helper_->GetProgramResourceiv(program, program_interface, index,
2021 kResultBucketId, GetResultShmId(),
2022 result.offset());
2023 WaitForCmd();
2024 if (length) {
2025 *length = result->GetNumResults();
2026 }
2027 if (result->GetNumResults() > 0) {
2028 if (params) {
2029 result->CopyResult(params);
2030 }
2031 GPU_CLIENT_LOG_CODE_BLOCK({
2032 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2033 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2034 }
2035 });
2036 return true;
2037 }
2038 return false;
2039 }
2040
GetProgramResourceiv(GLuint program,GLenum program_interface,GLuint index,GLsizei prop_count,const GLenum * props,GLsizei bufsize,GLsizei * length,GLint * params)2041 void GLES2Implementation::GetProgramResourceiv(GLuint program,
2042 GLenum program_interface,
2043 GLuint index,
2044 GLsizei prop_count,
2045 const GLenum* props,
2046 GLsizei bufsize,
2047 GLsizei* length,
2048 GLint* params) {
2049 GPU_CLIENT_SINGLE_THREAD_CHECK();
2050 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetProgramResourceiv(" << program
2051 << ", " << program_interface << ", " << index << ", "
2052 << prop_count << ", " << static_cast<const void*>(props)
2053 << ", " << bufsize << ", " << static_cast<void*>(length)
2054 << ", " << static_cast<void*>(params) << ")");
2055 if (prop_count < 0) {
2056 SetGLError(GL_INVALID_VALUE, "glGetProgramResourceiv", "prop_count < 0");
2057 return;
2058 }
2059 if (bufsize < 0) {
2060 SetGLError(GL_INVALID_VALUE, "glGetProgramResourceiv", "bufsize < 0");
2061 return;
2062 }
2063 TRACE_EVENT0("gpu", "GLES2::GetProgramResourceiv");
2064 GLsizei param_count = 0;
2065 bool success = share_group_->program_info_manager()->GetProgramResourceiv(
2066 this, program, program_interface, index, prop_count, props, bufsize,
2067 ¶m_count, params);
2068 if (length) {
2069 *length = param_count;
2070 }
2071 if (success && params) {
2072 GPU_CLIENT_LOG_CODE_BLOCK({
2073 for (GLsizei ii = 0; ii < param_count; ++ii) {
2074 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2075 }
2076 });
2077 }
2078 CheckGLError();
2079 }
2080
GetProgramResourceLocationHelper(GLuint program,GLenum program_interface,const char * name)2081 GLint GLES2Implementation::GetProgramResourceLocationHelper(
2082 GLuint program,
2083 GLenum program_interface,
2084 const char* name) {
2085 typedef cmds::GetProgramResourceLocation::Result Result;
2086 SetBucketAsCString(kResultBucketId, name);
2087 auto result = GetResultAs<Result>();
2088 if (!result) {
2089 return -1;
2090 }
2091 *result = -1;
2092 helper_->GetProgramResourceLocation(program, program_interface,
2093 kResultBucketId, GetResultShmId(),
2094 result.offset());
2095 WaitForCmd();
2096 helper_->SetBucketSize(kResultBucketId, 0);
2097 return *result;
2098 }
2099
GetProgramResourceLocation(GLuint program,GLenum program_interface,const char * name)2100 GLint GLES2Implementation::GetProgramResourceLocation(
2101 GLuint program,
2102 GLenum program_interface,
2103 const char* name) {
2104 GPU_CLIENT_SINGLE_THREAD_CHECK();
2105 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetProgramResourceLocation("
2106 << program << ", " << program_interface << ", " << name
2107 << ")");
2108 TRACE_EVENT0("gpu", "GLES2::GetProgramResourceLocation");
2109 GLint location =
2110 share_group_->program_info_manager()->GetProgramResourceLocation(
2111 this, program, program_interface, name);
2112 GPU_CLIENT_LOG("returned " << location);
2113 CheckGLError();
2114 return location;
2115 }
2116
LinkProgram(GLuint program)2117 void GLES2Implementation::LinkProgram(GLuint program) {
2118 GPU_CLIENT_SINGLE_THREAD_CHECK();
2119 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
2120 helper_->LinkProgram(program);
2121 share_group_->program_info_manager()->CreateInfo(program);
2122 CheckGLError();
2123 }
2124
ShaderBinary(GLsizei n,const GLuint * shaders,GLenum binaryformat,const void * binary,GLsizei length)2125 void GLES2Implementation::ShaderBinary(GLsizei n,
2126 const GLuint* shaders,
2127 GLenum binaryformat,
2128 const void* binary,
2129 GLsizei length) {
2130 GPU_CLIENT_SINGLE_THREAD_CHECK();
2131 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
2132 << static_cast<const void*>(shaders) << ", "
2133 << GLES2Util::GetStringEnum(binaryformat) << ", "
2134 << static_cast<const void*>(binary) << ", " << length
2135 << ")");
2136 if (n < 0) {
2137 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
2138 return;
2139 }
2140 if (length < 0) {
2141 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
2142 return;
2143 }
2144 // TODO(gman): ShaderBinary should use buckets.
2145 unsigned int shader_id_size = n * sizeof(*shaders);
2146 ScopedTransferBufferArray<GLint> buffer(shader_id_size + length, helper_,
2147 transfer_buffer_);
2148 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
2149 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
2150 return;
2151 }
2152 void* shader_ids = buffer.elements();
2153 void* shader_data = buffer.elements() + shader_id_size;
2154 memcpy(shader_ids, shaders, shader_id_size);
2155 memcpy(shader_data, binary, length);
2156 helper_->ShaderBinary(n, buffer.shm_id(), buffer.offset(), binaryformat,
2157 buffer.shm_id(), buffer.offset() + shader_id_size,
2158 length);
2159 CheckGLError();
2160 }
2161
PixelStorei(GLenum pname,GLint param)2162 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
2163 GPU_CLIENT_SINGLE_THREAD_CHECK();
2164 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
2165 << GLES2Util::GetStringPixelStore(pname) << ", " << param
2166 << ")");
2167 // We have to validate before caching these parameters because we use them
2168 // to compute image sizes on the client side.
2169 switch (pname) {
2170 case GL_PACK_ALIGNMENT:
2171 case GL_UNPACK_ALIGNMENT:
2172 if (param != 1 && param != 2 && param != 4 && param != 8) {
2173 SetGLError(GL_INVALID_VALUE, "glPixelStorei", "invalid param");
2174 return;
2175 }
2176 break;
2177 case GL_PACK_ROW_LENGTH:
2178 case GL_PACK_SKIP_PIXELS:
2179 case GL_PACK_SKIP_ROWS:
2180 case GL_UNPACK_IMAGE_HEIGHT:
2181 case GL_UNPACK_SKIP_IMAGES:
2182 if (capabilities_.major_version < 3) {
2183 SetGLError(GL_INVALID_ENUM, "glPixelStorei", "invalid pname");
2184 return;
2185 }
2186 if (param < 0) {
2187 SetGLError(GL_INVALID_VALUE, "glPixelStorei", "invalid param");
2188 return;
2189 }
2190 break;
2191 case GL_UNPACK_ROW_LENGTH:
2192 case GL_UNPACK_SKIP_ROWS:
2193 case GL_UNPACK_SKIP_PIXELS:
2194 // These parameters are always enabled in ES2 by EXT_unpack_subimage.
2195 if (param < 0) {
2196 SetGLError(GL_INVALID_VALUE, "glPixelStorei", "invalid param");
2197 return;
2198 }
2199 break;
2200 default:
2201 SetGLError(GL_INVALID_ENUM, "glPixelStorei", "invalid pname");
2202 return;
2203 }
2204 // Do not send SKIP parameters to the service side.
2205 // Handle them on the client side.
2206 switch (pname) {
2207 case GL_PACK_ALIGNMENT:
2208 pack_alignment_ = param;
2209 break;
2210 case GL_PACK_ROW_LENGTH:
2211 pack_row_length_ = param;
2212 break;
2213 case GL_PACK_SKIP_PIXELS:
2214 pack_skip_pixels_ = param;
2215 return;
2216 case GL_PACK_SKIP_ROWS:
2217 pack_skip_rows_ = param;
2218 return;
2219 case GL_UNPACK_ALIGNMENT:
2220 unpack_alignment_ = param;
2221 break;
2222 case GL_UNPACK_ROW_LENGTH:
2223 unpack_row_length_ = param;
2224 if (capabilities_.major_version < 3) {
2225 // In ES2 with EXT_unpack_subimage, it's handled on the client side
2226 // and there is no need to send it to the service side.
2227 return;
2228 }
2229 break;
2230 case GL_UNPACK_IMAGE_HEIGHT:
2231 unpack_image_height_ = param;
2232 break;
2233 case GL_UNPACK_SKIP_ROWS:
2234 unpack_skip_rows_ = param;
2235 return;
2236 case GL_UNPACK_SKIP_PIXELS:
2237 unpack_skip_pixels_ = param;
2238 return;
2239 case GL_UNPACK_SKIP_IMAGES:
2240 unpack_skip_images_ = param;
2241 return;
2242 default:
2243 NOTREACHED();
2244 break;
2245 }
2246 helper_->PixelStorei(pname, param);
2247 CheckGLError();
2248 }
2249
VertexAttribIPointer(GLuint index,GLint size,GLenum type,GLsizei stride,const void * ptr)2250 void GLES2Implementation::VertexAttribIPointer(GLuint index,
2251 GLint size,
2252 GLenum type,
2253 GLsizei stride,
2254 const void* ptr) {
2255 GPU_CLIENT_SINGLE_THREAD_CHECK();
2256 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer(" << index
2257 << ", " << size << ", "
2258 << GLES2Util::GetStringVertexAttribIType(type) << ", "
2259 << stride << ", " << ptr << ")");
2260 // Record the info on the client side.
2261 if (!vertex_array_object_manager_->SetAttribPointer(
2262 bound_array_buffer_, index, size, type, GL_FALSE, stride, ptr,
2263 GL_TRUE)) {
2264 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
2265 "client side arrays are not allowed in vertex array objects.");
2266 return;
2267 }
2268 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
2269 // Only report NON client side buffers to the service.
2270 if (!ValidateOffset("glVertexAttribIPointer",
2271 reinterpret_cast<GLintptr>(ptr))) {
2272 return;
2273 }
2274 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
2275 }
2276 CheckGLError();
2277 }
2278
VertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const void * ptr)2279 void GLES2Implementation::VertexAttribPointer(GLuint index,
2280 GLint size,
2281 GLenum type,
2282 GLboolean normalized,
2283 GLsizei stride,
2284 const void* ptr) {
2285 GPU_CLIENT_SINGLE_THREAD_CHECK();
2286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer(" << index
2287 << ", " << size << ", "
2288 << GLES2Util::GetStringVertexAttribType(type) << ", "
2289 << GLES2Util::GetStringBool(normalized) << ", " << stride
2290 << ", " << ptr << ")");
2291 // Record the info on the client side.
2292 if (!vertex_array_object_manager_->SetAttribPointer(
2293 bound_array_buffer_, index, size, type, normalized, stride, ptr,
2294 GL_FALSE)) {
2295 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
2296 "client side arrays are not allowed in vertex array objects.");
2297 return;
2298 }
2299 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
2300 // Only report NON client side buffers to the service.
2301 if (!ValidateOffset("glVertexAttribPointer",
2302 reinterpret_cast<GLintptr>(ptr))) {
2303 return;
2304 }
2305 helper_->VertexAttribPointer(index, size, type, normalized, stride,
2306 ToGLuint(ptr));
2307 }
2308 CheckGLError();
2309 }
2310
VertexAttribDivisorANGLE(GLuint index,GLuint divisor)2311 void GLES2Implementation::VertexAttribDivisorANGLE(GLuint index,
2312 GLuint divisor) {
2313 GPU_CLIENT_SINGLE_THREAD_CHECK();
2314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
2315 << index << ", " << divisor << ") ");
2316 // Record the info on the client side.
2317 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
2318 helper_->VertexAttribDivisorANGLE(index, divisor);
2319 CheckGLError();
2320 }
2321
BufferDataHelper(GLenum target,GLsizeiptr size,const void * data,GLenum usage)2322 void GLES2Implementation::BufferDataHelper(GLenum target,
2323 GLsizeiptr size,
2324 const void* data,
2325 GLenum usage) {
2326 if (!ValidateSize("glBufferData", size))
2327 return;
2328
2329 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
2330 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
2331 // bogus MSan report during a readback later. This is because MSan doesn't
2332 // understand shared memory and would assume we were reading back the same
2333 // unintialized data.
2334 if (data)
2335 __msan_check_mem_is_initialized(data, size);
2336 #endif
2337
2338 GLuint buffer_id;
2339 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
2340 if (!buffer_id) {
2341 return;
2342 }
2343
2344 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
2345 if (buffer)
2346 RemoveTransferBuffer(buffer);
2347
2348 // Create new buffer.
2349 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
2350 DCHECK(buffer);
2351 if (buffer->address() && data)
2352 memcpy(buffer->address(), data, size);
2353 return;
2354 }
2355
2356 if (IsReadbackUsage(usage)) {
2357 GLuint id = GetBoundBufferHelper(target);
2358 readback_buffer_shadow_tracker_->GetOrCreateBuffer(id, size);
2359 }
2360
2361 RemoveMappedBufferRangeByTarget(target);
2362
2363 // If there is no data just send BufferData
2364 if (size == 0 || !data) {
2365 helper_->BufferData(target, size, 0, 0, usage);
2366 return;
2367 }
2368
2369 // See if we can send all at once.
2370 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2371 if (!buffer.valid()) {
2372 return;
2373 }
2374
2375 if (buffer.size() >= static_cast<unsigned int>(size)) {
2376 memcpy(buffer.address(), data, size);
2377 helper_->BufferData(target, size, buffer.shm_id(), buffer.offset(), usage);
2378 return;
2379 }
2380
2381 // Make the buffer with BufferData then send via BufferSubData
2382 helper_->BufferData(target, size, 0, 0, usage);
2383 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
2384 CheckGLError();
2385 }
2386
BufferData(GLenum target,GLsizeiptr size,const void * data,GLenum usage)2387 void GLES2Implementation::BufferData(GLenum target,
2388 GLsizeiptr size,
2389 const void* data,
2390 GLenum usage) {
2391 GPU_CLIENT_SINGLE_THREAD_CHECK();
2392 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
2393 << GLES2Util::GetStringBufferTarget(target) << ", " << size
2394 << ", " << static_cast<const void*>(data) << ", "
2395 << GLES2Util::GetStringBufferUsage(usage) << ")");
2396 BufferDataHelper(target, size, data, usage);
2397 CheckGLError();
2398 }
2399
BufferSubDataHelper(GLenum target,GLintptr offset,GLsizeiptr size,const void * data)2400 void GLES2Implementation::BufferSubDataHelper(GLenum target,
2401 GLintptr offset,
2402 GLsizeiptr size,
2403 const void* data) {
2404 if (size == 0) {
2405 return;
2406 }
2407
2408 if (!ValidateSize("glBufferSubData", size) ||
2409 !ValidateOffset("glBufferSubData", offset)) {
2410 return;
2411 }
2412
2413 GLuint buffer_id;
2414 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
2415 if (!buffer_id) {
2416 return;
2417 }
2418 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
2419 if (!buffer) {
2420 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
2421 return;
2422 }
2423
2424 int32_t end = 0;
2425 int32_t buffer_size = buffer->size();
2426 if (!base::CheckAdd(offset, size).AssignIfValid(&end) ||
2427 end > buffer_size) {
2428 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
2429 return;
2430 }
2431
2432 if (buffer->address() && data)
2433 memcpy(static_cast<uint8_t*>(buffer->address()) + offset, data, size);
2434 return;
2435 }
2436
2437 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2438 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
2439 }
2440
BufferSubDataHelperImpl(GLenum target,GLintptr offset,GLsizeiptr size,const void * data,ScopedTransferBufferPtr * buffer)2441 void GLES2Implementation::BufferSubDataHelperImpl(
2442 GLenum target,
2443 GLintptr offset,
2444 GLsizeiptr size,
2445 const void* data,
2446 ScopedTransferBufferPtr* buffer) {
2447 DCHECK(buffer);
2448 DCHECK_GT(size, 0);
2449
2450 auto DoBufferSubData = [&](const std::array<uint32_t, 1>&,
2451 uint32_t copy_offset, uint32_t) {
2452 helper_->BufferSubData(target, offset + copy_offset, buffer->size(),
2453 buffer->shm_id(), buffer->offset());
2454 InvalidateReadbackBufferShadowDataCHROMIUM(GetBoundBufferHelper(target));
2455 };
2456
2457 if (!TransferArraysAndExecute(size, buffer, DoBufferSubData,
2458 static_cast<const int8_t*>(data))) {
2459 SetGLError(GL_OUT_OF_MEMORY, "glBufferSubData", "out of memory");
2460 }
2461 }
2462
BufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const void * data)2463 void GLES2Implementation::BufferSubData(GLenum target,
2464 GLintptr offset,
2465 GLsizeiptr size,
2466 const void* data) {
2467 GPU_CLIENT_SINGLE_THREAD_CHECK();
2468 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
2469 << GLES2Util::GetStringBufferTarget(target) << ", "
2470 << offset << ", " << size << ", "
2471 << static_cast<const void*>(data) << ")");
2472 BufferSubDataHelper(target, offset, size, data);
2473 CheckGLError();
2474 }
2475
MultiDrawArraysWEBGLHelper(GLenum mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)2476 void GLES2Implementation::MultiDrawArraysWEBGLHelper(GLenum mode,
2477 const GLint* firsts,
2478 const GLsizei* counts,
2479 GLsizei drawcount) {
2480 DCHECK_GT(drawcount, 0);
2481
2482 uint32_t buffer_size = ComputeCombinedCopySize(drawcount, firsts, counts);
2483 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2484
2485 helper_->MultiDrawBeginCHROMIUM(drawcount);
2486 auto DoMultiDraw = [&](const std::array<uint32_t, 2>& offsets, uint32_t,
2487 uint32_t copy_count) {
2488 helper_->MultiDrawArraysCHROMIUM(
2489 mode, buffer.shm_id(), buffer.offset() + offsets[0], buffer.shm_id(),
2490 buffer.offset() + offsets[1], copy_count);
2491 };
2492 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, firsts,
2493 counts)) {
2494 SetGLError(GL_OUT_OF_MEMORY, "glMultiDrawArraysWEBGL", "out of memory");
2495 }
2496 helper_->MultiDrawEndCHROMIUM();
2497 }
2498
MultiDrawArraysInstancedWEBGLHelper(GLenum mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instance_counts,GLsizei drawcount)2499 void GLES2Implementation::MultiDrawArraysInstancedWEBGLHelper(
2500 GLenum mode,
2501 const GLint* firsts,
2502 const GLsizei* counts,
2503 const GLsizei* instance_counts,
2504 GLsizei drawcount) {
2505 DCHECK_GT(drawcount, 0);
2506
2507 uint32_t buffer_size =
2508 ComputeCombinedCopySize(drawcount, firsts, counts, instance_counts);
2509 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2510
2511 helper_->MultiDrawBeginCHROMIUM(drawcount);
2512 auto DoMultiDraw = [&](const std::array<uint32_t, 3>& offsets, uint32_t,
2513 uint32_t copy_count) {
2514 helper_->MultiDrawArraysInstancedCHROMIUM(
2515 mode, buffer.shm_id(), buffer.offset() + offsets[0], buffer.shm_id(),
2516 buffer.offset() + offsets[1], buffer.shm_id(),
2517 buffer.offset() + offsets[2], copy_count);
2518 };
2519 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, firsts, counts,
2520 instance_counts)) {
2521 SetGLError(GL_OUT_OF_MEMORY, "glMultiDrawArraysInstancedWEBGL",
2522 "out of memory");
2523 }
2524 helper_->MultiDrawEndCHROMIUM();
2525 }
2526
MultiDrawArraysInstancedBaseInstanceWEBGLHelper(GLenum mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instance_counts,const GLuint * baseinstances,GLsizei drawcount)2527 void GLES2Implementation::MultiDrawArraysInstancedBaseInstanceWEBGLHelper(
2528 GLenum mode,
2529 const GLint* firsts,
2530 const GLsizei* counts,
2531 const GLsizei* instance_counts,
2532 const GLuint* baseinstances,
2533 GLsizei drawcount) {
2534 DCHECK_GT(drawcount, 0);
2535
2536 uint32_t buffer_size = ComputeCombinedCopySize(
2537 drawcount, firsts, counts, instance_counts, baseinstances);
2538 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2539
2540 helper_->MultiDrawBeginCHROMIUM(drawcount);
2541 auto DoMultiDraw = [&](const std::array<uint32_t, 4>& offsets, uint32_t,
2542 uint32_t copy_count) {
2543 helper_->MultiDrawArraysInstancedBaseInstanceCHROMIUM(
2544 mode, buffer.shm_id(), buffer.offset() + offsets[0], buffer.shm_id(),
2545 buffer.offset() + offsets[1], buffer.shm_id(),
2546 buffer.offset() + offsets[2], buffer.shm_id(),
2547 buffer.offset() + offsets[3], copy_count);
2548 };
2549 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, firsts, counts,
2550 instance_counts, baseinstances)) {
2551 SetGLError(GL_OUT_OF_MEMORY, "glMultiDrawArraysInstancedBaseInstanceWEBGL",
2552 "out of memory");
2553 }
2554 helper_->MultiDrawEndCHROMIUM();
2555 }
2556
MultiDrawElementsWEBGLHelper(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,GLsizei drawcount)2557 void GLES2Implementation::MultiDrawElementsWEBGLHelper(GLenum mode,
2558 const GLsizei* counts,
2559 GLenum type,
2560 const GLsizei* offsets,
2561 GLsizei drawcount) {
2562 DCHECK_GT(drawcount, 0);
2563
2564 uint32_t buffer_size = ComputeCombinedCopySize(drawcount, counts, offsets);
2565 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2566
2567 helper_->MultiDrawBeginCHROMIUM(drawcount);
2568 auto DoMultiDraw = [&](const std::array<uint32_t, 2>& offsets, uint32_t,
2569 uint32_t copy_count) {
2570 helper_->MultiDrawElementsCHROMIUM(
2571 mode, buffer.shm_id(), buffer.offset() + offsets[0], type,
2572 buffer.shm_id(), buffer.offset() + offsets[1], copy_count);
2573 };
2574 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, counts,
2575 offsets)) {
2576 SetGLError(GL_OUT_OF_MEMORY, "glMultiDrawElementsWEBGL", "out of memory");
2577 }
2578 helper_->MultiDrawEndCHROMIUM();
2579 }
2580
MultiDrawElementsInstancedWEBGLHelper(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,const GLsizei * instance_counts,GLsizei drawcount)2581 void GLES2Implementation::MultiDrawElementsInstancedWEBGLHelper(
2582 GLenum mode,
2583 const GLsizei* counts,
2584 GLenum type,
2585 const GLsizei* offsets,
2586 const GLsizei* instance_counts,
2587 GLsizei drawcount) {
2588 DCHECK_GT(drawcount, 0);
2589
2590 uint32_t buffer_size =
2591 ComputeCombinedCopySize(drawcount, counts, offsets, instance_counts);
2592 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2593
2594 helper_->MultiDrawBeginCHROMIUM(drawcount);
2595 auto DoMultiDraw = [&](const std::array<uint32_t, 3>& offsets, uint32_t,
2596 uint32_t copy_count) {
2597 helper_->MultiDrawElementsInstancedCHROMIUM(
2598 mode, buffer.shm_id(), buffer.offset() + offsets[0], type,
2599 buffer.shm_id(), buffer.offset() + offsets[1], buffer.shm_id(),
2600 buffer.offset() + offsets[2], copy_count);
2601 };
2602 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, counts,
2603 offsets, instance_counts)) {
2604 SetGLError(GL_OUT_OF_MEMORY, "glMultiDrawElementsInstancedWEBGL",
2605 "out of memory");
2606 }
2607 helper_->MultiDrawEndCHROMIUM();
2608 }
2609
2610 void GLES2Implementation::
MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGLHelper(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,const GLsizei * instance_counts,const GLint * basevertices,const GLuint * baseinstances,GLsizei drawcount)2611 MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGLHelper(
2612 GLenum mode,
2613 const GLsizei* counts,
2614 GLenum type,
2615 const GLsizei* offsets,
2616 const GLsizei* instance_counts,
2617 const GLint* basevertices,
2618 const GLuint* baseinstances,
2619 GLsizei drawcount) {
2620 DCHECK_GT(drawcount, 0);
2621
2622 uint32_t buffer_size = ComputeCombinedCopySize(
2623 drawcount, counts, offsets, instance_counts, basevertices, baseinstances);
2624 ScopedTransferBufferPtr buffer(buffer_size, helper_, transfer_buffer_);
2625
2626 helper_->MultiDrawBeginCHROMIUM(drawcount);
2627 auto DoMultiDraw = [&](const std::array<uint32_t, 5>& offsets, uint32_t,
2628 uint32_t copy_count) {
2629 helper_->MultiDrawElementsInstancedBaseVertexBaseInstanceCHROMIUM(
2630 mode, buffer.shm_id(), buffer.offset() + offsets[0], type,
2631 buffer.shm_id(), buffer.offset() + offsets[1], buffer.shm_id(),
2632 buffer.offset() + offsets[2], buffer.shm_id(),
2633 buffer.offset() + offsets[3], buffer.shm_id(),
2634 buffer.offset() + offsets[4], copy_count);
2635 };
2636 if (!TransferArraysAndExecute(drawcount, &buffer, DoMultiDraw, counts,
2637 offsets, instance_counts, basevertices,
2638 baseinstances)) {
2639 SetGLError(GL_OUT_OF_MEMORY,
2640 "glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL",
2641 "out of memory");
2642 }
2643 helper_->MultiDrawEndCHROMIUM();
2644 }
2645
MultiDrawArraysWEBGL(GLenum mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)2646 void GLES2Implementation::MultiDrawArraysWEBGL(GLenum mode,
2647 const GLint* firsts,
2648 const GLsizei* counts,
2649 GLsizei drawcount) {
2650 GPU_CLIENT_SINGLE_THREAD_CHECK();
2651 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMultiDrawArraysWEBGL("
2652 << GLES2Util::GetStringDrawMode(mode) << ", " << firsts
2653 << ", " << counts << ", " << drawcount << ")");
2654 if (drawcount < 0) {
2655 SetGLError(GL_INVALID_VALUE, "glMultiDrawArraysWEBGL", "drawcount < 0");
2656 return;
2657 }
2658 if (drawcount == 0) {
2659 return;
2660 }
2661 // This is for an extension for WebGL which doesn't support client side arrays
2662 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2663 SetGLError(GL_INVALID_OPERATION, "glMultiDrawArraysWEBGL",
2664 "Missing array buffer for vertex attribute");
2665 return;
2666 }
2667 MultiDrawArraysWEBGLHelper(mode, firsts, counts, drawcount);
2668 CheckGLError();
2669 }
2670
MultiDrawArraysInstancedWEBGL(GLenum mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instance_counts,GLsizei drawcount)2671 void GLES2Implementation::MultiDrawArraysInstancedWEBGL(
2672 GLenum mode,
2673 const GLint* firsts,
2674 const GLsizei* counts,
2675 const GLsizei* instance_counts,
2676 GLsizei drawcount) {
2677 GPU_CLIENT_SINGLE_THREAD_CHECK();
2678 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMultiDrawArraysInstancedWEBGL("
2679 << GLES2Util::GetStringDrawMode(mode) << ", " << firsts
2680 << ", " << counts << ", " << instance_counts << ", "
2681 << drawcount << ")");
2682 if (drawcount < 0) {
2683 SetGLError(GL_INVALID_VALUE, "glMultiDrawArraysWEBGLInstanced",
2684 "drawcount < 0");
2685 return;
2686 }
2687 if (drawcount == 0) {
2688 return;
2689 }
2690 // This is for an extension for WebGL which doesn't support client side arrays
2691 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2692 SetGLError(GL_INVALID_OPERATION, "glMultiDrawArraysWEBGLInstanced",
2693 "Missing array buffer for vertex attribute");
2694 return;
2695 }
2696 MultiDrawArraysInstancedWEBGLHelper(mode, firsts, counts, instance_counts,
2697 drawcount);
2698 CheckGLError();
2699 }
2700
MultiDrawArraysInstancedBaseInstanceWEBGL(GLenum mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instance_counts,const GLuint * baseinstances,GLsizei drawcount)2701 void GLES2Implementation::MultiDrawArraysInstancedBaseInstanceWEBGL(
2702 GLenum mode,
2703 const GLint* firsts,
2704 const GLsizei* counts,
2705 const GLsizei* instance_counts,
2706 const GLuint* baseinstances,
2707 GLsizei drawcount) {
2708 GPU_CLIENT_SINGLE_THREAD_CHECK();
2709 GPU_CLIENT_LOG("[" << GetLogPrefix()
2710 << "] glMultiDrawArraysInstancedBaseInstanceWEBGL("
2711 << GLES2Util::GetStringDrawMode(mode) << ", " << firsts
2712 << ", " << counts << ", " << instance_counts << ", "
2713 << baseinstances << ", " << drawcount << ")");
2714 if (drawcount < 0) {
2715 SetGLError(GL_INVALID_VALUE, "glMultiDrawArraysInstancedBaseInstanceWEBGL",
2716 "drawcount < 0");
2717 return;
2718 }
2719 if (drawcount == 0) {
2720 return;
2721 }
2722 // This is for an extension for WebGL which doesn't support client side arrays
2723 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2724 SetGLError(GL_INVALID_OPERATION,
2725 "glMultiDrawArraysInstancedBaseInstanceWEBGL",
2726 "Missing array buffer for vertex attribute");
2727 return;
2728 }
2729 MultiDrawArraysInstancedBaseInstanceWEBGLHelper(
2730 mode, firsts, counts, instance_counts, baseinstances, drawcount);
2731 CheckGLError();
2732 }
2733
MultiDrawElementsWEBGL(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,GLsizei drawcount)2734 void GLES2Implementation::MultiDrawElementsWEBGL(GLenum mode,
2735 const GLsizei* counts,
2736 GLenum type,
2737 const GLsizei* offsets,
2738 GLsizei drawcount) {
2739 GPU_CLIENT_SINGLE_THREAD_CHECK();
2740 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMultiDrawElementsWEBGL("
2741 << GLES2Util::GetStringDrawMode(mode) << ", " << counts
2742 << ", " << GLES2Util::GetStringIndexType(type) << ", "
2743 << offsets << ", " << drawcount << ")");
2744 if (drawcount < 0) {
2745 SetGLError(GL_INVALID_VALUE, "glMultiDrawElementsWEBGL", "drawcount < 0");
2746 return;
2747 }
2748 if (drawcount == 0) {
2749 return;
2750 }
2751 // This is for an extension for WebGL which doesn't support client side arrays
2752 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
2753 SetGLError(GL_INVALID_OPERATION, "glMultiDrawElementsWEBGL",
2754 "No element array buffer");
2755 return;
2756 }
2757 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2758 SetGLError(GL_INVALID_OPERATION, "glMultiDrawElementsWEBGL",
2759 "Missing array buffer for vertex attribute");
2760 return;
2761 }
2762 MultiDrawElementsWEBGLHelper(mode, counts, type, offsets, drawcount);
2763 CheckGLError();
2764 }
2765
MultiDrawElementsInstancedWEBGL(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,const GLsizei * instance_counts,GLsizei drawcount)2766 void GLES2Implementation::MultiDrawElementsInstancedWEBGL(
2767 GLenum mode,
2768 const GLsizei* counts,
2769 GLenum type,
2770 const GLsizei* offsets,
2771 const GLsizei* instance_counts,
2772 GLsizei drawcount) {
2773 GPU_CLIENT_SINGLE_THREAD_CHECK();
2774 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMultiDrawElementsInstancedWEBGL("
2775 << GLES2Util::GetStringDrawMode(mode) << ", " << counts
2776 << ", " << GLES2Util::GetStringIndexType(type) << ", "
2777 << offsets << ", " << instance_counts << ", " << drawcount
2778 << ")");
2779 if (drawcount < 0) {
2780 SetGLError(GL_INVALID_VALUE, "glMultiDrawElementsInstancedWEBGL",
2781 "drawcount < 0");
2782 return;
2783 }
2784 if (drawcount == 0) {
2785 return;
2786 }
2787 // This is for an extension for WebGL which doesn't support client side arrays
2788 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
2789 SetGLError(GL_INVALID_OPERATION, "glMultiDrawElementsInstancedWEBGL",
2790 "No element array buffer");
2791 return;
2792 }
2793 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2794 SetGLError(GL_INVALID_OPERATION, "glMultiDrawElementsInstancedWEBGL",
2795 "Missing array buffer for vertex attribute");
2796 return;
2797 }
2798 MultiDrawElementsInstancedWEBGLHelper(mode, counts, type, offsets,
2799 instance_counts, drawcount);
2800 CheckGLError();
2801 }
2802
MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(GLenum mode,const GLsizei * counts,GLenum type,const GLsizei * offsets,const GLsizei * instance_counts,const GLint * basevertices,const GLuint * baseinstances,GLsizei drawcount)2803 void GLES2Implementation::MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(
2804 GLenum mode,
2805 const GLsizei* counts,
2806 GLenum type,
2807 const GLsizei* offsets,
2808 const GLsizei* instance_counts,
2809 const GLint* basevertices,
2810 const GLuint* baseinstances,
2811 GLsizei drawcount) {
2812 GPU_CLIENT_SINGLE_THREAD_CHECK();
2813 GPU_CLIENT_LOG(
2814 "[" << GetLogPrefix()
2815 << "] glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL("
2816 << GLES2Util::GetStringDrawMode(mode) << ", " << counts << ", "
2817 << GLES2Util::GetStringIndexType(type) << ", " << offsets << ", "
2818 << instance_counts << ", " << basevertices << ", " << baseinstances
2819 << drawcount << ")");
2820 if (drawcount < 0) {
2821 SetGLError(GL_INVALID_VALUE, "glMultiDrawElementsInstancedWEBGL",
2822 "drawcount < 0");
2823 return;
2824 }
2825 if (drawcount == 0) {
2826 return;
2827 }
2828 // This is for an extension for WebGL which doesn't support client side arrays
2829 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
2830 SetGLError(GL_INVALID_OPERATION,
2831 "glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL",
2832 "No element array buffer");
2833 return;
2834 }
2835 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
2836 SetGLError(GL_INVALID_OPERATION,
2837 "glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL",
2838 "Missing array buffer for vertex attribute");
2839 return;
2840 }
2841 MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGLHelper(
2842 mode, counts, type, offsets, instance_counts, basevertices, baseinstances,
2843 drawcount);
2844 CheckGLError();
2845 }
2846
RemoveTransferBuffer(BufferTracker::Buffer * buffer)2847 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
2848 int32_t token = buffer->last_usage_token();
2849
2850 if (token) {
2851 if (helper_->HasTokenPassed(token))
2852 buffer_tracker_->Free(buffer);
2853 else
2854 buffer_tracker_->FreePendingToken(buffer, token);
2855 } else {
2856 buffer_tracker_->Free(buffer);
2857 }
2858
2859 buffer_tracker_->RemoveBuffer(buffer->id());
2860 }
2861
GetBoundPixelTransferBuffer(GLenum target,const char * function_name,GLuint * buffer_id)2862 bool GLES2Implementation::GetBoundPixelTransferBuffer(GLenum target,
2863 const char* function_name,
2864 GLuint* buffer_id) {
2865 *buffer_id = 0;
2866
2867 switch (target) {
2868 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2869 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
2870 break;
2871 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2872 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
2873 break;
2874 default:
2875 // Unknown target
2876 return false;
2877 }
2878 if (!*buffer_id) {
2879 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
2880 }
2881 return true;
2882 }
2883
GetBoundPixelTransferBufferIfValid(GLuint buffer_id,const char * function_name,GLuint offset,GLsizei size)2884 BufferTracker::Buffer* GLES2Implementation::GetBoundPixelTransferBufferIfValid(
2885 GLuint buffer_id,
2886 const char* function_name,
2887 GLuint offset,
2888 GLsizei size) {
2889 DCHECK(buffer_id);
2890 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
2891 if (!buffer) {
2892 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
2893 return nullptr;
2894 }
2895 if (buffer->mapped()) {
2896 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
2897 return nullptr;
2898 }
2899 base::CheckedNumeric<uint32_t> buffer_offset = buffer->shm_offset();
2900 buffer_offset += offset;
2901 if (!buffer_offset.IsValid()) {
2902 SetGLError(GL_INVALID_VALUE, function_name, "offset to large");
2903 return nullptr;
2904 }
2905 base::CheckedNumeric<uint32_t> required_size = offset;
2906 required_size += size;
2907 if (!required_size.IsValid() ||
2908 buffer->size() < required_size.ValueOrDefault(0)) {
2909 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
2910 return nullptr;
2911 }
2912 return buffer;
2913 }
2914
InvalidateReadbackBufferShadowDataCHROMIUM(GLuint buffer_id)2915 void GLES2Implementation::InvalidateReadbackBufferShadowDataCHROMIUM(
2916 GLuint buffer_id) {
2917 readback_buffer_shadow_tracker_->OnBufferWrite(buffer_id);
2918 }
2919
CompressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLsizei image_size,const void * data)2920 void GLES2Implementation::CompressedTexImage2D(GLenum target,
2921 GLint level,
2922 GLenum internalformat,
2923 GLsizei width,
2924 GLsizei height,
2925 GLint border,
2926 GLsizei image_size,
2927 const void* data) {
2928 GPU_CLIENT_SINGLE_THREAD_CHECK();
2929 GPU_CLIENT_LOG(
2930 "[" << GetLogPrefix() << "] glCompressedTexImage2D("
2931 << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", "
2932 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2933 << width << ", " << height << ", " << border << ", " << image_size
2934 << ", " << static_cast<const void*>(data) << ")");
2935 if (width < 0 || height < 0 || level < 0) {
2936 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
2937 return;
2938 }
2939 if (border != 0) {
2940 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
2941 return;
2942 }
2943 // If there's a pixel unpack buffer bound use it when issuing
2944 // CompressedTexImage2D.
2945 if (bound_pixel_unpack_transfer_buffer_id_) {
2946 GLuint offset = ToGLuint(data);
2947 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
2948 bound_pixel_unpack_transfer_buffer_id_, "glCompressedTexImage2D",
2949 offset, image_size);
2950 if (buffer && buffer->shm_id() != -1) {
2951 helper_->CompressedTexImage2D(target, level, internalformat, width,
2952 height, image_size, buffer->shm_id(),
2953 buffer->shm_offset() + offset);
2954 buffer->set_last_usage_token(helper_->InsertToken());
2955 }
2956 return;
2957 }
2958 if (bound_pixel_unpack_buffer_) {
2959 helper_->CompressedTexImage2D(target, level, internalformat, width, height,
2960 image_size, 0, ToGLuint(data));
2961 } else if (data) {
2962 SetBucketContents(kResultBucketId, data, image_size);
2963 helper_->CompressedTexImage2DBucket(target, level, internalformat, width,
2964 height, kResultBucketId);
2965 // Free the bucket. This is not required but it does free up the memory.
2966 // and we don't have to wait for the result so from the client's perspective
2967 // it's cheap.
2968 helper_->SetBucketSize(kResultBucketId, 0);
2969 } else {
2970 helper_->CompressedTexImage2D(target, level, internalformat, width, height,
2971 image_size, 0, 0);
2972 }
2973 CheckGLError();
2974 }
2975
CompressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei image_size,const void * data)2976 void GLES2Implementation::CompressedTexSubImage2D(GLenum target,
2977 GLint level,
2978 GLint xoffset,
2979 GLint yoffset,
2980 GLsizei width,
2981 GLsizei height,
2982 GLenum format,
2983 GLsizei image_size,
2984 const void* data) {
2985 GPU_CLIENT_SINGLE_THREAD_CHECK();
2986 GPU_CLIENT_LOG(
2987 "[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
2988 << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", "
2989 << xoffset << ", " << yoffset << ", " << width << ", " << height
2990 << ", " << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2991 << image_size << ", " << static_cast<const void*>(data) << ")");
2992 if (width < 0 || height < 0 || level < 0) {
2993 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
2994 return;
2995 }
2996 // If there's a pixel unpack buffer bound use it when issuing
2997 // CompressedTexSubImage2D.
2998 if (bound_pixel_unpack_transfer_buffer_id_) {
2999 GLuint offset = ToGLuint(data);
3000 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3001 bound_pixel_unpack_transfer_buffer_id_, "glCompressedTexSubImage2D",
3002 offset, image_size);
3003 if (buffer && buffer->shm_id() != -1) {
3004 helper_->CompressedTexSubImage2D(
3005 target, level, xoffset, yoffset, width, height, format, image_size,
3006 buffer->shm_id(), buffer->shm_offset() + offset);
3007 buffer->set_last_usage_token(helper_->InsertToken());
3008 CheckGLError();
3009 }
3010 return;
3011 }
3012 if (bound_pixel_unpack_buffer_) {
3013 helper_->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
3014 height, format, image_size, 0,
3015 ToGLuint(data));
3016 } else if (data) {
3017 SetBucketContents(kResultBucketId, data, image_size);
3018 helper_->CompressedTexSubImage2DBucket(target, level, xoffset, yoffset,
3019 width, height, format,
3020 kResultBucketId);
3021 // Free the bucket. This is not required but it does free up the memory.
3022 // and we don't have to wait for the result so from the client's perspective
3023 // it's cheap.
3024 helper_->SetBucketSize(kResultBucketId, 0);
3025 } else {
3026 helper_->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
3027 height, format, image_size, 0, 0);
3028 }
3029 CheckGLError();
3030 }
3031
CompressedTexImage3D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLsizei image_size,const void * data)3032 void GLES2Implementation::CompressedTexImage3D(GLenum target,
3033 GLint level,
3034 GLenum internalformat,
3035 GLsizei width,
3036 GLsizei height,
3037 GLsizei depth,
3038 GLint border,
3039 GLsizei image_size,
3040 const void* data) {
3041 GPU_CLIENT_SINGLE_THREAD_CHECK();
3042 GPU_CLIENT_LOG(
3043 "[" << GetLogPrefix() << "] glCompressedTexImage3D("
3044 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level
3045 << ", " << GLES2Util::GetStringCompressedTextureFormat(internalformat)
3046 << ", " << width << ", " << height << ", " << depth << ", " << border
3047 << ", " << image_size << ", " << static_cast<const void*>(data)
3048 << ")");
3049 if (width < 0 || height < 0 || depth < 0 || level < 0) {
3050 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
3051 return;
3052 }
3053 if (border != 0) {
3054 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
3055 return;
3056 }
3057 // If there's a pixel unpack buffer bound use it when issuing
3058 // CompressedTexImage3D.
3059 if (bound_pixel_unpack_transfer_buffer_id_) {
3060 GLuint offset = ToGLuint(data);
3061 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3062 bound_pixel_unpack_transfer_buffer_id_, "glCompressedTexImage3D",
3063 offset, image_size);
3064 if (buffer && buffer->shm_id() != -1) {
3065 helper_->CompressedTexImage3D(target, level, internalformat, width,
3066 height, depth, image_size, buffer->shm_id(),
3067 buffer->shm_offset() + offset);
3068 buffer->set_last_usage_token(helper_->InsertToken());
3069 }
3070 return;
3071 }
3072 if (bound_pixel_unpack_buffer_) {
3073 helper_->CompressedTexImage3D(target, level, internalformat, width, height,
3074 depth, image_size, 0, ToGLuint(data));
3075 } else if (data) {
3076 SetBucketContents(kResultBucketId, data, image_size);
3077 helper_->CompressedTexImage3DBucket(target, level, internalformat, width,
3078 height, depth, kResultBucketId);
3079 // Free the bucket. This is not required but it does free up the memory.
3080 // and we don't have to wait for the result so from the client's perspective
3081 // it's cheap.
3082 helper_->SetBucketSize(kResultBucketId, 0);
3083 } else {
3084 helper_->CompressedTexImage3D(target, level, internalformat, width, height,
3085 depth, image_size, 0, 0);
3086 }
3087 CheckGLError();
3088 }
3089
CompressedTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei image_size,const void * data)3090 void GLES2Implementation::CompressedTexSubImage3D(GLenum target,
3091 GLint level,
3092 GLint xoffset,
3093 GLint yoffset,
3094 GLint zoffset,
3095 GLsizei width,
3096 GLsizei height,
3097 GLsizei depth,
3098 GLenum format,
3099 GLsizei image_size,
3100 const void* data) {
3101 GPU_CLIENT_SINGLE_THREAD_CHECK();
3102 GPU_CLIENT_LOG(
3103 "[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
3104 << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", "
3105 << xoffset << ", " << yoffset << ", " << zoffset << ", " << width
3106 << ", " << height << ", " << depth << ", "
3107 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
3108 << image_size << ", " << static_cast<const void*>(data) << ")");
3109 if (width < 0 || height < 0 || depth < 0 || level < 0) {
3110 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
3111 return;
3112 }
3113 // If there's a pixel unpack buffer bound use it when issuing
3114 // CompressedTexSubImage3D.
3115 if (bound_pixel_unpack_transfer_buffer_id_) {
3116 GLuint offset = ToGLuint(data);
3117 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3118 bound_pixel_unpack_transfer_buffer_id_, "glCompressedTexSubImage3D",
3119 offset, image_size);
3120 if (buffer && buffer->shm_id() != -1) {
3121 helper_->CompressedTexSubImage3D(
3122 target, level, xoffset, yoffset, zoffset, width, height, depth,
3123 format, image_size, buffer->shm_id(), buffer->shm_offset() + offset);
3124 buffer->set_last_usage_token(helper_->InsertToken());
3125 CheckGLError();
3126 }
3127 return;
3128 }
3129 if (bound_pixel_unpack_buffer_) {
3130 helper_->CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset,
3131 width, height, depth, format, image_size,
3132 0, ToGLuint(data));
3133 } else if (data) {
3134 SetBucketContents(kResultBucketId, data, image_size);
3135 helper_->CompressedTexSubImage3DBucket(target, level, xoffset, yoffset,
3136 zoffset, width, height, depth,
3137 format, kResultBucketId);
3138 // Free the bucket. This is not required but it does free up the memory.
3139 // and we don't have to wait for the result so from the client's perspective
3140 // it's cheap.
3141 helper_->SetBucketSize(kResultBucketId, 0);
3142 } else {
3143 helper_->CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset,
3144 width, height, depth, format, image_size,
3145 0, 0);
3146 }
3147 CheckGLError();
3148 }
3149
GetUnpackParameters(Dimension dimension)3150 PixelStoreParams GLES2Implementation::GetUnpackParameters(Dimension dimension) {
3151 PixelStoreParams params;
3152 params.alignment = unpack_alignment_;
3153 params.row_length = unpack_row_length_;
3154 params.skip_pixels = unpack_skip_pixels_;
3155 params.skip_rows = unpack_skip_rows_;
3156 if (dimension == k3D) {
3157 params.image_height = unpack_image_height_;
3158 params.skip_images = unpack_skip_images_;
3159 }
3160 return params;
3161 }
3162
PrepareNextSwapId(SwapCompletedCallback completion_callback,PresentationCallback presentation_callback)3163 uint64_t GLES2Implementation::PrepareNextSwapId(
3164 SwapCompletedCallback completion_callback,
3165 PresentationCallback presentation_callback) {
3166 uint64_t swap_id = swap_id_++;
3167 pending_swap_callbacks_.emplace(swap_id, std::move(completion_callback));
3168 if (!presentation_callback.is_null()) {
3169 pending_presentation_callbacks_.emplace(swap_id,
3170 std::move(presentation_callback));
3171 }
3172 return swap_id;
3173 }
3174
TexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)3175 void GLES2Implementation::TexImage2D(GLenum target,
3176 GLint level,
3177 GLint internalformat,
3178 GLsizei width,
3179 GLsizei height,
3180 GLint border,
3181 GLenum format,
3182 GLenum type,
3183 const void* pixels) {
3184 const char* func_name = "glTexImage2D";
3185 GPU_CLIENT_SINGLE_THREAD_CHECK();
3186 GPU_CLIENT_LOG(
3187 "[" << GetLogPrefix() << "] glTexImage2D("
3188 << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", "
3189 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3190 << width << ", " << height << ", " << border << ", "
3191 << GLES2Util::GetStringTextureFormat(format) << ", "
3192 << GLES2Util::GetStringPixelType(type) << ", "
3193 << static_cast<const void*>(pixels) << ")");
3194 if (level < 0 || height < 0 || width < 0) {
3195 SetGLError(GL_INVALID_VALUE, func_name, "dimension < 0");
3196 return;
3197 }
3198 if (border != 0) {
3199 SetGLError(GL_INVALID_VALUE, func_name, "border != 0");
3200 return;
3201 }
3202 if ((bound_pixel_unpack_buffer_ || pixels) &&
3203 (unpack_skip_pixels_ + width >
3204 (unpack_row_length_ ? unpack_row_length_ : width))) {
3205 // This is WebGL 2 specific constraints, but we do it for all ES3 contexts.
3206 SetGLError(GL_INVALID_OPERATION, func_name,
3207 "invalid unpack params combination");
3208 return;
3209 }
3210
3211 uint32_t size;
3212 uint32_t unpadded_row_size;
3213 uint32_t padded_row_size;
3214 uint32_t skip_size;
3215 PixelStoreParams params = GetUnpackParameters(k2D);
3216
3217 if (!GLES2Util::ComputeImageDataSizesES3(
3218 width, height, 1, format, type, params, &size, &unpadded_row_size,
3219 &padded_row_size, &skip_size, nullptr)) {
3220 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3221 return;
3222 }
3223
3224 if (bound_pixel_unpack_buffer_) {
3225 base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels);
3226 offset += skip_size;
3227 if (!offset.IsValid()) {
3228 SetGLError(GL_INVALID_VALUE, func_name, "skip size too large");
3229 return;
3230 }
3231 helper_->TexImage2D(target, level, internalformat, width, height, format,
3232 type, 0, offset.ValueOrDefault(0));
3233 CheckGLError();
3234 return;
3235 }
3236
3237 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
3238 if (bound_pixel_unpack_transfer_buffer_id_) {
3239 if (unpack_row_length_ > 0 || unpack_image_height_ > 0 ||
3240 unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 ||
3241 unpack_skip_images_ > 0) {
3242 SetGLError(GL_INVALID_OPERATION, func_name,
3243 "No ES3 pack parameters with pixel unpack transfer buffer.");
3244 return;
3245 }
3246 DCHECK_EQ(0u, skip_size);
3247 GLuint offset = ToGLuint(pixels);
3248 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3249 bound_pixel_unpack_transfer_buffer_id_, func_name, offset, size);
3250 if (buffer && buffer->shm_id() != -1) {
3251 helper_->TexImage2D(target, level, internalformat, width, height, format,
3252 type, buffer->shm_id(),
3253 buffer->shm_offset() + offset);
3254 buffer->set_last_usage_token(helper_->InsertToken());
3255 CheckGLError();
3256 }
3257 return;
3258 }
3259
3260 // If there's no data just issue TexImage2D
3261 if (!pixels || width == 0 || height == 0) {
3262 helper_->TexImage2D(target, level, internalformat, width, height, format,
3263 type, 0, 0);
3264 CheckGLError();
3265 return;
3266 }
3267
3268 // Compute the advance bytes per row on the service side.
3269 // Note |size| is recomputed here if needed.
3270 uint32_t service_padded_row_size;
3271 if (unpack_row_length_ > 0 && unpack_row_length_ != width) {
3272 // All parameters have been applied to the data that are sent to the
3273 // service side except UNPACK_ALIGNMENT.
3274 PixelStoreParams service_params;
3275 service_params.alignment = unpack_alignment_;
3276 if (!GLES2Util::ComputeImageDataSizesES3(
3277 width, height, 1, format, type, service_params, &size, nullptr,
3278 &service_padded_row_size, nullptr, nullptr)) {
3279 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3280 return;
3281 }
3282 } else {
3283 service_padded_row_size = padded_row_size;
3284 }
3285
3286 // advance pixels pointer past the skip rows and skip pixels
3287 pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size;
3288
3289 // Check if we can send it all at once.
3290 int32_t shm_id = 0;
3291 uint32_t shm_offset = 0;
3292 void* buffer_pointer = nullptr;
3293
3294 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
3295 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
3296
3297 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
3298 shm_id = transfer_alloc.shm_id();
3299 shm_offset = transfer_alloc.offset();
3300 buffer_pointer = transfer_alloc.address();
3301 } else if (size < max_extra_transfer_buffer_size_) {
3302 mapped_alloc.Reset(size);
3303 if (mapped_alloc.valid()) {
3304 transfer_alloc.Discard();
3305
3306 mapped_alloc.SetFlushAfterRelease(true);
3307 shm_id = mapped_alloc.shm_id();
3308 shm_offset = mapped_alloc.offset();
3309 buffer_pointer = mapped_alloc.address();
3310 }
3311 }
3312
3313 if (buffer_pointer) {
3314 CopyRectToBuffer(pixels, height, unpadded_row_size, padded_row_size,
3315 buffer_pointer, service_padded_row_size);
3316 helper_->TexImage2D(target, level, internalformat, width, height, format,
3317 type, shm_id, shm_offset);
3318 CheckGLError();
3319 return;
3320 }
3321
3322 // No, so send it using TexSubImage2D.
3323 helper_->TexImage2D(target, level, internalformat, width, height, format,
3324 type, 0, 0);
3325 TexSubImage2DImpl(target, level, 0, 0, width, height, format, type,
3326 unpadded_row_size, pixels, padded_row_size, GL_TRUE,
3327 &transfer_alloc, service_padded_row_size);
3328 CheckGLError();
3329 }
3330
TexImage3D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,const void * pixels)3331 void GLES2Implementation::TexImage3D(GLenum target,
3332 GLint level,
3333 GLint internalformat,
3334 GLsizei width,
3335 GLsizei height,
3336 GLsizei depth,
3337 GLint border,
3338 GLenum format,
3339 GLenum type,
3340 const void* pixels) {
3341 const char* func_name = "glTexImage3D";
3342 GPU_CLIENT_SINGLE_THREAD_CHECK();
3343 GPU_CLIENT_LOG(
3344 "[" << GetLogPrefix() << "] glTexImage3D("
3345 << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", "
3346 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3347 << width << ", " << height << ", " << depth << ", " << border << ", "
3348 << GLES2Util::GetStringTextureFormat(format) << ", "
3349 << GLES2Util::GetStringPixelType(type) << ", "
3350 << static_cast<const void*>(pixels) << ")");
3351 if (level < 0 || height < 0 || width < 0 || depth < 0) {
3352 SetGLError(GL_INVALID_VALUE, func_name, "dimension < 0");
3353 return;
3354 }
3355 if (border != 0) {
3356 SetGLError(GL_INVALID_VALUE, func_name, "border != 0");
3357 return;
3358 }
3359 if ((bound_pixel_unpack_buffer_ || pixels) &&
3360 ((unpack_skip_pixels_ + width >
3361 (unpack_row_length_ ? unpack_row_length_ : width)) ||
3362 (unpack_skip_rows_ + height >
3363 (unpack_image_height_ ? unpack_image_height_ : height)))) {
3364 // This is WebGL 2 specific constraints, but we do it for all ES3 contexts.
3365 SetGLError(GL_INVALID_OPERATION, func_name,
3366 "invalid unpack params combination");
3367 return;
3368 }
3369
3370 uint32_t size;
3371 uint32_t unpadded_row_size;
3372 uint32_t padded_row_size;
3373 uint32_t skip_size;
3374 PixelStoreParams params = GetUnpackParameters(k3D);
3375 if (!GLES2Util::ComputeImageDataSizesES3(
3376 width, height, depth, format, type, params, &size, &unpadded_row_size,
3377 &padded_row_size, &skip_size, nullptr)) {
3378 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3379 return;
3380 }
3381
3382 if (bound_pixel_unpack_buffer_) {
3383 base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels);
3384 offset += skip_size;
3385 if (!offset.IsValid()) {
3386 SetGLError(GL_INVALID_VALUE, func_name, "skip size too large");
3387 return;
3388 }
3389 helper_->TexImage3D(target, level, internalformat, width, height, depth,
3390 format, type, 0, offset.ValueOrDefault(0));
3391 CheckGLError();
3392 return;
3393 }
3394
3395 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
3396 if (bound_pixel_unpack_transfer_buffer_id_) {
3397 if (unpack_row_length_ > 0 || unpack_image_height_ > 0 ||
3398 unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 ||
3399 unpack_skip_images_ > 0) {
3400 SetGLError(GL_INVALID_OPERATION, func_name,
3401 "No ES3 pack parameters with pixel unpack transfer buffer.");
3402 return;
3403 }
3404 DCHECK_EQ(0u, skip_size);
3405 GLuint offset = ToGLuint(pixels);
3406 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3407 bound_pixel_unpack_transfer_buffer_id_, func_name, offset, size);
3408 if (buffer && buffer->shm_id() != -1) {
3409 helper_->TexImage3D(target, level, internalformat, width, height, depth,
3410 format, type, buffer->shm_id(),
3411 buffer->shm_offset() + offset);
3412 buffer->set_last_usage_token(helper_->InsertToken());
3413 CheckGLError();
3414 }
3415 return;
3416 }
3417
3418 // If there's no data just issue TexImage3D
3419 if (!pixels || width == 0 || height == 0 || depth == 0) {
3420 helper_->TexImage3D(target, level, internalformat, width, height, depth,
3421 format, type, 0, 0);
3422 CheckGLError();
3423 return;
3424 }
3425
3426 // Compute the advance bytes per row on the service side.
3427 // Note |size| is recomputed here if needed.
3428 uint32_t service_padded_row_size;
3429 if ((unpack_row_length_ > 0 && unpack_row_length_ != width) ||
3430 (unpack_image_height_ > 0 && unpack_image_height_ != height)) {
3431 // All parameters have been applied to the data that are sent to the
3432 // service side except UNPACK_ALIGNMENT.
3433 PixelStoreParams service_params;
3434 service_params.alignment = unpack_alignment_;
3435 if (!GLES2Util::ComputeImageDataSizesES3(
3436 width, height, depth, format, type, service_params, &size, nullptr,
3437 &service_padded_row_size, nullptr, nullptr)) {
3438 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3439 return;
3440 }
3441 } else {
3442 service_padded_row_size = padded_row_size;
3443 }
3444 uint32_t src_height =
3445 unpack_image_height_ > 0 ? unpack_image_height_ : height;
3446
3447 // advance pixels pointer past the skip images/rows/pixels
3448 pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size;
3449
3450 // Check if we can send it all at once.
3451 int32_t shm_id = 0;
3452 uint32_t shm_offset = 0;
3453 void* buffer_pointer = nullptr;
3454
3455 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
3456 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
3457
3458 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
3459 shm_id = transfer_alloc.shm_id();
3460 shm_offset = transfer_alloc.offset();
3461 buffer_pointer = transfer_alloc.address();
3462 } else if (size < max_extra_transfer_buffer_size_) {
3463 mapped_alloc.Reset(size);
3464 if (mapped_alloc.valid()) {
3465 transfer_alloc.Discard();
3466
3467 mapped_alloc.SetFlushAfterRelease(true);
3468 shm_id = mapped_alloc.shm_id();
3469 shm_offset = mapped_alloc.offset();
3470 buffer_pointer = mapped_alloc.address();
3471 }
3472 }
3473
3474 if (buffer_pointer) {
3475 for (GLsizei z = 0; z < depth; ++z) {
3476 CopyRectToBuffer(pixels, height, unpadded_row_size, padded_row_size,
3477 buffer_pointer, service_padded_row_size);
3478 pixels = reinterpret_cast<const int8_t*>(pixels) +
3479 padded_row_size * src_height;
3480 buffer_pointer = reinterpret_cast<int8_t*>(buffer_pointer) +
3481 service_padded_row_size * height;
3482 }
3483 helper_->TexImage3D(target, level, internalformat, width, height, depth,
3484 format, type, shm_id, shm_offset);
3485 CheckGLError();
3486 return;
3487 }
3488
3489 // No, so send it using TexSubImage3D.
3490 helper_->TexImage3D(target, level, internalformat, width, height, depth,
3491 format, type, 0, 0);
3492 TexSubImage3DImpl(target, level, 0, 0, 0, width, height, depth, format, type,
3493 unpadded_row_size, pixels, padded_row_size, GL_TRUE,
3494 &transfer_alloc, service_padded_row_size);
3495 CheckGLError();
3496 }
3497
TexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)3498 void GLES2Implementation::TexSubImage2D(GLenum target,
3499 GLint level,
3500 GLint xoffset,
3501 GLint yoffset,
3502 GLsizei width,
3503 GLsizei height,
3504 GLenum format,
3505 GLenum type,
3506 const void* pixels) {
3507 const char* func_name = "glTexSubImage2D";
3508 GPU_CLIENT_SINGLE_THREAD_CHECK();
3509 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
3510 << GLES2Util::GetStringTextureTarget(target) << ", "
3511 << level << ", " << xoffset << ", " << yoffset << ", "
3512 << width << ", " << height << ", "
3513 << GLES2Util::GetStringTextureFormat(format) << ", "
3514 << GLES2Util::GetStringPixelType(type) << ", "
3515 << static_cast<const void*>(pixels) << ")");
3516
3517 if (level < 0 || height < 0 || width < 0 || xoffset < 0 || yoffset < 0) {
3518 SetGLError(GL_INVALID_VALUE, func_name, "dimension < 0");
3519 return;
3520 }
3521 if (unpack_skip_pixels_ + width >
3522 (unpack_row_length_ ? unpack_row_length_ : width)) {
3523 // This is WebGL 2 specific constraints, but we do it for all ES3 contexts.
3524 SetGLError(GL_INVALID_OPERATION, func_name,
3525 "invalid unpack params combination");
3526 return;
3527 }
3528
3529 uint32_t size;
3530 uint32_t unpadded_row_size;
3531 uint32_t padded_row_size;
3532 uint32_t skip_size;
3533 PixelStoreParams params = GetUnpackParameters(k2D);
3534 if (!GLES2Util::ComputeImageDataSizesES3(
3535 width, height, 1, format, type, params, &size, &unpadded_row_size,
3536 &padded_row_size, &skip_size, nullptr)) {
3537 SetGLError(GL_INVALID_VALUE, func_name, "image size to large");
3538 return;
3539 }
3540
3541 if (bound_pixel_unpack_buffer_) {
3542 base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels);
3543 offset += skip_size;
3544 if (!offset.IsValid()) {
3545 SetGLError(GL_INVALID_VALUE, func_name, "skip size too large");
3546 return;
3547 }
3548 helper_->TexSubImage2D(target, level, xoffset, yoffset, width, height,
3549 format, type, 0, offset.ValueOrDefault(0), false);
3550 CheckGLError();
3551 return;
3552 }
3553
3554 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
3555 if (bound_pixel_unpack_transfer_buffer_id_) {
3556 if (unpack_row_length_ > 0 || unpack_image_height_ > 0 ||
3557 unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 ||
3558 unpack_skip_images_ > 0) {
3559 SetGLError(GL_INVALID_OPERATION, func_name,
3560 "No ES3 pack parameters with pixel unpack transfer buffer.");
3561 return;
3562 }
3563 DCHECK_EQ(0u, skip_size);
3564 GLuint offset = ToGLuint(pixels);
3565 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3566 bound_pixel_unpack_transfer_buffer_id_, func_name, offset, size);
3567 if (buffer && buffer->shm_id() != -1) {
3568 helper_->TexSubImage2D(target, level, xoffset, yoffset, width, height,
3569 format, type, buffer->shm_id(),
3570 buffer->shm_offset() + offset, false);
3571 buffer->set_last_usage_token(helper_->InsertToken());
3572 CheckGLError();
3573 }
3574 return;
3575 }
3576
3577 if (width == 0 || height == 0) {
3578 // No need to worry about pixel data.
3579 helper_->TexSubImage2D(target, level, xoffset, yoffset, width, height,
3580 format, type, 0, 0, false);
3581 CheckGLError();
3582 return;
3583 }
3584
3585 // Compute the advance bytes per row on the service side.
3586 // Note |size| is recomputed here if needed.
3587 uint32_t service_padded_row_size;
3588 if (unpack_row_length_ > 0 && unpack_row_length_ != width) {
3589 // All parameters have been applied to the data that are sent to the
3590 // service side except UNPACK_ALIGNMENT.
3591 PixelStoreParams service_params;
3592 service_params.alignment = unpack_alignment_;
3593 if (!GLES2Util::ComputeImageDataSizesES3(
3594 width, height, 1, format, type, service_params, &size, nullptr,
3595 &service_padded_row_size, nullptr, nullptr)) {
3596 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3597 return;
3598 }
3599 } else {
3600 service_padded_row_size = padded_row_size;
3601 }
3602
3603 // advance pixels pointer past the skip rows and skip pixels
3604 pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size;
3605
3606 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
3607 base::CheckedNumeric<GLint> checked_xoffset = xoffset;
3608 checked_xoffset += width;
3609 if (!checked_xoffset.IsValid()) {
3610 SetGLError(GL_INVALID_VALUE, "TexSubImage2D", "xoffset + width overflows");
3611 return;
3612 }
3613 base::CheckedNumeric<GLint> checked_yoffset = yoffset;
3614 checked_yoffset += height;
3615 if (!checked_yoffset.IsValid()) {
3616 SetGLError(GL_INVALID_VALUE, "TexSubImage2D", "yoffset + height overflows");
3617 return;
3618 }
3619 TexSubImage2DImpl(target, level, xoffset, yoffset, width, height, format,
3620 type, unpadded_row_size, pixels, padded_row_size, GL_FALSE,
3621 &buffer, service_padded_row_size);
3622 CheckGLError();
3623 }
3624
TexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * pixels)3625 void GLES2Implementation::TexSubImage3D(GLenum target,
3626 GLint level,
3627 GLint xoffset,
3628 GLint yoffset,
3629 GLint zoffset,
3630 GLsizei width,
3631 GLsizei height,
3632 GLsizei depth,
3633 GLenum format,
3634 GLenum type,
3635 const void* pixels) {
3636 const char* func_name = "glTexSubImage3D";
3637 GPU_CLIENT_SINGLE_THREAD_CHECK();
3638 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
3639 << GLES2Util::GetStringTextureTarget(target) << ", "
3640 << level << ", " << xoffset << ", " << yoffset << ", "
3641 << zoffset << ", " << width << ", " << height << ", "
3642 << depth << ", "
3643 << GLES2Util::GetStringTextureFormat(format) << ", "
3644 << GLES2Util::GetStringPixelType(type) << ", "
3645 << static_cast<const void*>(pixels) << ")");
3646
3647 if (level < 0 || height < 0 || width < 0 || depth < 0 || xoffset < 0 ||
3648 yoffset < 0 || zoffset < 0) {
3649 SetGLError(GL_INVALID_VALUE, func_name, "dimension < 0");
3650 return;
3651 }
3652 if ((unpack_skip_pixels_ + width >
3653 (unpack_row_length_ ? unpack_row_length_ : width)) ||
3654 (unpack_skip_rows_ + height >
3655 (unpack_image_height_ ? unpack_image_height_ : height))) {
3656 // This is WebGL 2 specific constraints, but we do it for all ES3 contexts.
3657 SetGLError(GL_INVALID_OPERATION, func_name,
3658 "invalid unpack params combination");
3659 return;
3660 }
3661
3662 uint32_t size;
3663 uint32_t unpadded_row_size;
3664 uint32_t padded_row_size;
3665 uint32_t skip_size;
3666 PixelStoreParams params = GetUnpackParameters(k3D);
3667 if (!GLES2Util::ComputeImageDataSizesES3(
3668 width, height, depth, format, type, params, &size, &unpadded_row_size,
3669 &padded_row_size, &skip_size, nullptr)) {
3670 SetGLError(GL_INVALID_VALUE, func_name, "image size to large");
3671 return;
3672 }
3673
3674 if (bound_pixel_unpack_buffer_) {
3675 base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels);
3676 offset += skip_size;
3677 if (!offset.IsValid()) {
3678 SetGLError(GL_INVALID_VALUE, func_name, "skip size too large");
3679 return;
3680 }
3681 helper_->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
3682 height, depth, format, type, 0,
3683 offset.ValueOrDefault(0), false);
3684 CheckGLError();
3685 return;
3686 }
3687
3688 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
3689 if (bound_pixel_unpack_transfer_buffer_id_) {
3690 if (unpack_row_length_ > 0 || unpack_image_height_ > 0 ||
3691 unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 ||
3692 unpack_skip_images_ > 0) {
3693 SetGLError(GL_INVALID_OPERATION, func_name,
3694 "No ES3 pack parameters with pixel unpack transfer buffer.");
3695 return;
3696 }
3697 DCHECK_EQ(0u, skip_size);
3698 GLuint offset = ToGLuint(pixels);
3699 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
3700 bound_pixel_unpack_transfer_buffer_id_, func_name, offset, size);
3701 if (buffer && buffer->shm_id() != -1) {
3702 helper_->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
3703 height, depth, format, type, buffer->shm_id(),
3704 buffer->shm_offset() + offset, false);
3705 buffer->set_last_usage_token(helper_->InsertToken());
3706 CheckGLError();
3707 }
3708 return;
3709 }
3710
3711 if (width == 0 || height == 0 || depth == 0) {
3712 // No need to worry about pixel data.
3713 helper_->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
3714 height, depth, format, type, 0, 0, false);
3715 CheckGLError();
3716 return;
3717 }
3718
3719 // Compute the advance bytes per row on the service side
3720 // Note |size| is recomputed here if needed.
3721 uint32_t service_padded_row_size;
3722 if ((unpack_row_length_ > 0 && unpack_row_length_ != width) ||
3723 (unpack_image_height_ > 0 && unpack_image_height_ != height)) {
3724 PixelStoreParams service_params;
3725 service_params.alignment = unpack_alignment_;
3726 if (!GLES2Util::ComputeImageDataSizesES3(
3727 width, height, depth, format, type, service_params, &size, nullptr,
3728 &service_padded_row_size, nullptr, nullptr)) {
3729 SetGLError(GL_INVALID_VALUE, func_name, "image size too large");
3730 return;
3731 }
3732 } else {
3733 service_padded_row_size = padded_row_size;
3734 }
3735
3736 // advance pixels pointer past the skip images/rows/pixels
3737 pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size;
3738
3739 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
3740 base::CheckedNumeric<GLint> checked_xoffset = xoffset;
3741 checked_xoffset += width;
3742 if (!checked_xoffset.IsValid()) {
3743 SetGLError(GL_INVALID_VALUE, "TexSubImage3D", "xoffset + width overflows");
3744 return;
3745 }
3746 base::CheckedNumeric<GLint> checked_yoffset = yoffset;
3747 checked_yoffset += height;
3748 if (!checked_yoffset.IsValid()) {
3749 SetGLError(GL_INVALID_VALUE, "TexSubImage3D", "yoffset + height overflows");
3750 return;
3751 }
3752 base::CheckedNumeric<GLint> checked_zoffset = zoffset;
3753 checked_zoffset += depth;
3754 if (!checked_zoffset.IsValid()) {
3755 SetGLError(GL_INVALID_VALUE, "TexSubImage3D", "zoffset + depth overflows");
3756 return;
3757 }
3758 TexSubImage3DImpl(target, level, xoffset, yoffset, zoffset, width, height,
3759 depth, format, type, unpadded_row_size, pixels,
3760 padded_row_size, GL_FALSE, &buffer,
3761 service_padded_row_size);
3762 CheckGLError();
3763 }
3764
ComputeNumRowsThatFitInBuffer(uint32_t padded_row_size,uint32_t unpadded_row_size,unsigned int size,GLsizei remaining_rows)3765 static GLint ComputeNumRowsThatFitInBuffer(uint32_t padded_row_size,
3766 uint32_t unpadded_row_size,
3767 unsigned int size,
3768 GLsizei remaining_rows) {
3769 DCHECK_GE(unpadded_row_size, 0u);
3770 if (padded_row_size == 0) {
3771 return 1;
3772 }
3773 GLint num_rows = size / padded_row_size;
3774 if (num_rows + 1 == remaining_rows &&
3775 size - num_rows * padded_row_size >= unpadded_row_size) {
3776 num_rows++;
3777 }
3778 return num_rows;
3779 }
3780
TexSubImage2DImpl(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,uint32_t unpadded_row_size,const void * pixels,uint32_t pixels_padded_row_size,GLboolean internal,ScopedTransferBufferPtr * buffer,uint32_t buffer_padded_row_size)3781 void GLES2Implementation::TexSubImage2DImpl(GLenum target,
3782 GLint level,
3783 GLint xoffset,
3784 GLint yoffset,
3785 GLsizei width,
3786 GLsizei height,
3787 GLenum format,
3788 GLenum type,
3789 uint32_t unpadded_row_size,
3790 const void* pixels,
3791 uint32_t pixels_padded_row_size,
3792 GLboolean internal,
3793 ScopedTransferBufferPtr* buffer,
3794 uint32_t buffer_padded_row_size) {
3795 DCHECK(buffer);
3796 DCHECK_GE(level, 0);
3797 DCHECK_GT(height, 0);
3798 DCHECK_GT(width, 0);
3799 DCHECK_GE(xoffset, 0);
3800 DCHECK_GE(yoffset, 0);
3801
3802 const int8_t* source = reinterpret_cast<const int8_t*>(pixels);
3803 // Transfer by rows.
3804 while (height) {
3805 unsigned int desired_size =
3806 buffer_padded_row_size * (height - 1) + unpadded_row_size;
3807 if (!buffer->valid() || buffer->size() == 0) {
3808 buffer->Reset(desired_size);
3809 if (!buffer->valid()) {
3810 return;
3811 }
3812 }
3813
3814 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3815 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
3816 num_rows = std::min(num_rows, height);
3817 CopyRectToBuffer(source, num_rows, unpadded_row_size,
3818 pixels_padded_row_size, buffer->address(),
3819 buffer_padded_row_size);
3820 helper_->TexSubImage2D(target, level, xoffset, yoffset, width, num_rows,
3821 format, type, buffer->shm_id(), buffer->offset(),
3822 internal);
3823 buffer->Release();
3824 yoffset += num_rows;
3825 source += num_rows * pixels_padded_row_size;
3826 height -= num_rows;
3827 }
3828 }
3829
TexSubImage3DImpl(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,uint32_t unpadded_row_size,const void * pixels,uint32_t pixels_padded_row_size,GLboolean internal,ScopedTransferBufferPtr * buffer,uint32_t buffer_padded_row_size)3830 void GLES2Implementation::TexSubImage3DImpl(GLenum target,
3831 GLint level,
3832 GLint xoffset,
3833 GLint yoffset,
3834 GLsizei zoffset,
3835 GLsizei width,
3836 GLsizei height,
3837 GLsizei depth,
3838 GLenum format,
3839 GLenum type,
3840 uint32_t unpadded_row_size,
3841 const void* pixels,
3842 uint32_t pixels_padded_row_size,
3843 GLboolean internal,
3844 ScopedTransferBufferPtr* buffer,
3845 uint32_t buffer_padded_row_size) {
3846 DCHECK(buffer);
3847 DCHECK_GE(level, 0);
3848 DCHECK_GT(width, 0);
3849 DCHECK_GT(height, 0);
3850 DCHECK_GT(depth, 0);
3851 DCHECK_GE(xoffset, 0);
3852 DCHECK_GE(yoffset, 0);
3853 DCHECK_GE(zoffset, 0);
3854 const int8_t* source = reinterpret_cast<const int8_t*>(pixels);
3855 GLsizei total_rows = height * depth;
3856 GLint row_index = 0, depth_index = 0;
3857 while (total_rows) {
3858 // Each time, we either copy one or more images, or copy one or more rows
3859 // within a single image, depending on the buffer size limit.
3860 GLsizei max_rows;
3861 unsigned int desired_size;
3862 if (row_index > 0) {
3863 // We are in the middle of an image. Send the remaining of the image.
3864 max_rows = height - row_index;
3865 if (total_rows <= height) {
3866 // Last image, so last row is unpadded.
3867 desired_size =
3868 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
3869 } else {
3870 desired_size = buffer_padded_row_size * max_rows;
3871 }
3872 } else {
3873 // Send all the remaining data if possible.
3874 max_rows = total_rows;
3875 desired_size =
3876 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
3877 }
3878 if (!buffer->valid() || buffer->size() == 0) {
3879 buffer->Reset(desired_size);
3880 if (!buffer->valid()) {
3881 return;
3882 }
3883 }
3884 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3885 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
3886 num_rows = std::min(num_rows, max_rows);
3887 GLint num_images = num_rows / height;
3888 GLsizei my_height, my_depth;
3889 if (num_images > 0) {
3890 num_rows = num_images * height;
3891 my_height = height;
3892 my_depth = num_images;
3893 } else {
3894 my_height = num_rows;
3895 my_depth = 1;
3896 }
3897
3898 if (num_images > 0) {
3899 int8_t* buffer_pointer = reinterpret_cast<int8_t*>(buffer->address());
3900 uint32_t src_height =
3901 unpack_image_height_ > 0 ? unpack_image_height_ : height;
3902 uint32_t image_size_dst = buffer_padded_row_size * height;
3903 uint32_t image_size_src = pixels_padded_row_size * src_height;
3904 for (GLint ii = 0; ii < num_images; ++ii) {
3905 CopyRectToBuffer(source + ii * image_size_src, my_height,
3906 unpadded_row_size, pixels_padded_row_size,
3907 buffer_pointer + ii * image_size_dst,
3908 buffer_padded_row_size);
3909 }
3910 } else {
3911 CopyRectToBuffer(source, my_height, unpadded_row_size,
3912 pixels_padded_row_size, buffer->address(),
3913 buffer_padded_row_size);
3914 }
3915 helper_->TexSubImage3D(target, level, xoffset, yoffset + row_index,
3916 zoffset + depth_index, width, my_height, my_depth,
3917 format, type, buffer->shm_id(), buffer->offset(),
3918 internal);
3919 buffer->Release();
3920
3921 total_rows -= num_rows;
3922 if (total_rows > 0) {
3923 GLint num_image_paddings;
3924 if (num_images > 0) {
3925 DCHECK_EQ(row_index, 0);
3926 depth_index += num_images;
3927 num_image_paddings = num_images;
3928 } else {
3929 row_index = (row_index + my_height) % height;
3930 num_image_paddings = 0;
3931 if (my_height > 0 && row_index == 0) {
3932 depth_index++;
3933 num_image_paddings++;
3934 }
3935 }
3936 source += num_rows * pixels_padded_row_size;
3937 if (unpack_image_height_ > height && num_image_paddings > 0) {
3938 source += num_image_paddings * (unpack_image_height_ - height) *
3939 pixels_padded_row_size;
3940 }
3941 }
3942 }
3943 }
3944
GetResultNameHelper(GLsizei bufsize,GLsizei * length,char * name)3945 void GLES2Implementation::GetResultNameHelper(GLsizei bufsize,
3946 GLsizei* length,
3947 char* name) {
3948 // Length of string (without final \0) that we will write to the buffer.
3949 GLsizei max_length = 0;
3950 if (name && (bufsize > 0)) {
3951 std::vector<int8_t> str;
3952 GetBucketContents(kResultBucketId, &str);
3953 if (!str.empty()) {
3954 DCHECK_LE(str.size(), static_cast<size_t>(INT_MAX));
3955 // Note: both bufsize and str.size() count/include the terminating \0.
3956 max_length = std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
3957 }
3958 memcpy(name, str.data(), max_length);
3959 name[max_length] = '\0';
3960 }
3961 if (length) {
3962 *length = max_length;
3963 }
3964 }
3965
GetActiveAttribHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)3966 bool GLES2Implementation::GetActiveAttribHelper(GLuint program,
3967 GLuint index,
3968 GLsizei bufsize,
3969 GLsizei* length,
3970 GLint* size,
3971 GLenum* type,
3972 char* name) {
3973 // Clear the bucket so if the command fails nothing will be in it.
3974 helper_->SetBucketSize(kResultBucketId, 0);
3975 typedef cmds::GetActiveAttrib::Result Result;
3976 auto result = GetResultAs<Result>();
3977 if (!result) {
3978 return false;
3979 }
3980 // Set as failed so if the command fails we'll recover.
3981 result->success = false;
3982 helper_->GetActiveAttrib(program, index, kResultBucketId, GetResultShmId(),
3983 result.offset());
3984 WaitForCmd();
3985 bool success = !!result->success;
3986 if (success) {
3987 if (size) {
3988 *size = result->size;
3989 }
3990 if (type) {
3991 *type = result->type;
3992 }
3993 // Note: this can invalidate |result|.
3994 GetResultNameHelper(bufsize, length, name);
3995 }
3996 return success;
3997 }
3998
GetActiveAttrib(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)3999 void GLES2Implementation::GetActiveAttrib(GLuint program,
4000 GLuint index,
4001 GLsizei bufsize,
4002 GLsizei* length,
4003 GLint* size,
4004 GLenum* type,
4005 char* name) {
4006 GPU_CLIENT_SINGLE_THREAD_CHECK();
4007 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib(" << program
4008 << ", " << index << ", " << bufsize << ", "
4009 << static_cast<const void*>(length) << ", "
4010 << static_cast<const void*>(size) << ", "
4011 << static_cast<const void*>(type) << ", "
4012 << static_cast<const void*>(name) << ", ");
4013 if (bufsize < 0) {
4014 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
4015 return;
4016 }
4017 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
4018 bool success = share_group_->program_info_manager()->GetActiveAttrib(
4019 this, program, index, bufsize, length, size, type, name);
4020 if (success) {
4021 if (size) {
4022 GPU_CLIENT_LOG(" size: " << *size);
4023 }
4024 if (type) {
4025 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
4026 }
4027 if (name) {
4028 GPU_CLIENT_LOG(" name: " << name);
4029 }
4030 }
4031 CheckGLError();
4032 }
4033
GetActiveUniformHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)4034 bool GLES2Implementation::GetActiveUniformHelper(GLuint program,
4035 GLuint index,
4036 GLsizei bufsize,
4037 GLsizei* length,
4038 GLint* size,
4039 GLenum* type,
4040 char* name) {
4041 // Clear the bucket so if the command fails nothing will be in it.
4042 helper_->SetBucketSize(kResultBucketId, 0);
4043 typedef cmds::GetActiveUniform::Result Result;
4044 auto result = GetResultAs<Result>();
4045 if (!result) {
4046 return false;
4047 }
4048 // Set as failed so if the command fails we'll recover.
4049 result->success = false;
4050 helper_->GetActiveUniform(program, index, kResultBucketId, GetResultShmId(),
4051 result.offset());
4052 WaitForCmd();
4053 bool success = !!result->success;
4054 if (success) {
4055 if (size) {
4056 *size = result->size;
4057 }
4058 if (type) {
4059 *type = result->type;
4060 }
4061 // Note: this can invalidate |result|.
4062 GetResultNameHelper(bufsize, length, name);
4063 }
4064 return success;
4065 }
4066
GetActiveUniform(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)4067 void GLES2Implementation::GetActiveUniform(GLuint program,
4068 GLuint index,
4069 GLsizei bufsize,
4070 GLsizei* length,
4071 GLint* size,
4072 GLenum* type,
4073 char* name) {
4074 GPU_CLIENT_SINGLE_THREAD_CHECK();
4075 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform(" << program
4076 << ", " << index << ", " << bufsize << ", "
4077 << static_cast<const void*>(length) << ", "
4078 << static_cast<const void*>(size) << ", "
4079 << static_cast<const void*>(type) << ", "
4080 << static_cast<const void*>(name) << ", ");
4081 if (bufsize < 0) {
4082 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
4083 return;
4084 }
4085 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
4086 bool success = share_group_->program_info_manager()->GetActiveUniform(
4087 this, program, index, bufsize, length, size, type, name);
4088 if (success) {
4089 if (size) {
4090 GPU_CLIENT_LOG(" size: " << *size);
4091 }
4092 if (type) {
4093 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
4094 }
4095 if (name) {
4096 GPU_CLIENT_LOG(" name: " << name);
4097 }
4098 }
4099 CheckGLError();
4100 }
4101
GetActiveUniformBlockNameHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,char * name)4102 bool GLES2Implementation::GetActiveUniformBlockNameHelper(GLuint program,
4103 GLuint index,
4104 GLsizei bufsize,
4105 GLsizei* length,
4106 char* name) {
4107 DCHECK_LE(0, bufsize);
4108 // Clear the bucket so if the command fails nothing will be in it.
4109 helper_->SetBucketSize(kResultBucketId, 0);
4110 typedef cmds::GetActiveUniformBlockName::Result Result;
4111 auto result = GetResultAs<Result>();
4112 if (!result) {
4113 return false;
4114 }
4115 // Set as failed so if the command fails we'll recover.
4116 *result = 0;
4117 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
4118 GetResultShmId(), result.offset());
4119 WaitForCmd();
4120 bool success = !!result;
4121 if (success) {
4122 // Note: this can invalidate |result|.
4123 GetResultNameHelper(bufsize, length, name);
4124 }
4125 return success;
4126 }
4127
GetActiveUniformBlockName(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,char * name)4128 void GLES2Implementation::GetActiveUniformBlockName(GLuint program,
4129 GLuint index,
4130 GLsizei bufsize,
4131 GLsizei* length,
4132 char* name) {
4133 GPU_CLIENT_SINGLE_THREAD_CHECK();
4134 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
4135 << program << ", " << index << ", " << bufsize << ", "
4136 << static_cast<const void*>(length) << ", "
4137 << static_cast<const void*>(name) << ")");
4138 if (bufsize < 0) {
4139 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
4140 return;
4141 }
4142 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
4143 bool success =
4144 share_group_->program_info_manager()->GetActiveUniformBlockName(
4145 this, program, index, bufsize, length, name);
4146 if (success) {
4147 if (name) {
4148 GPU_CLIENT_LOG(" name: " << name);
4149 }
4150 }
4151 CheckGLError();
4152 }
4153
GetActiveUniformBlockivHelper(GLuint program,GLuint index,GLenum pname,GLint * params)4154 bool GLES2Implementation::GetActiveUniformBlockivHelper(GLuint program,
4155 GLuint index,
4156 GLenum pname,
4157 GLint* params) {
4158 typedef cmds::GetActiveUniformBlockiv::Result Result;
4159 auto result = GetResultAs<Result>();
4160 if (!result) {
4161 return false;
4162 }
4163 result->SetNumResults(0);
4164 helper_->GetActiveUniformBlockiv(program, index, pname, GetResultShmId(),
4165 result.offset());
4166 WaitForCmd();
4167 if (result->GetNumResults() > 0) {
4168 if (params) {
4169 result->CopyResult(params);
4170 }
4171 GPU_CLIENT_LOG_CODE_BLOCK({
4172 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4173 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4174 }
4175 });
4176 return true;
4177 }
4178 return false;
4179 }
4180
GetActiveUniformBlockiv(GLuint program,GLuint index,GLenum pname,GLint * params)4181 void GLES2Implementation::GetActiveUniformBlockiv(GLuint program,
4182 GLuint index,
4183 GLenum pname,
4184 GLint* params) {
4185 GPU_CLIENT_SINGLE_THREAD_CHECK();
4186 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
4187 << program << ", " << index << ", "
4188 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
4189 << static_cast<const void*>(params) << ")");
4190 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
4191 bool success = share_group_->program_info_manager()->GetActiveUniformBlockiv(
4192 this, program, index, pname, params);
4193 if (success) {
4194 if (params) {
4195 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
4196 // be more than one value returned in params.
4197 GPU_CLIENT_LOG(" params: " << params[0]);
4198 }
4199 }
4200 CheckGLError();
4201 }
4202
GetActiveUniformsivHelper(GLuint program,GLsizei count,const GLuint * indices,GLenum pname,GLint * params)4203 bool GLES2Implementation::GetActiveUniformsivHelper(GLuint program,
4204 GLsizei count,
4205 const GLuint* indices,
4206 GLenum pname,
4207 GLint* params) {
4208 base::CheckedNumeric<uint32_t> bytes = count;
4209 bytes *= sizeof(GLuint);
4210 if (!bytes.IsValid()) {
4211 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
4212 return false;
4213 }
4214 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
4215 typedef cmds::GetActiveUniformsiv::Result Result;
4216 auto result = GetResultAs<Result>();
4217 if (!result) {
4218 return false;
4219 }
4220 result->SetNumResults(0);
4221 helper_->GetActiveUniformsiv(program, kResultBucketId, pname,
4222 GetResultShmId(), result.offset());
4223 WaitForCmd();
4224 bool success = result->GetNumResults() == count;
4225 if (success) {
4226 if (params) {
4227 result->CopyResult(params);
4228 }
4229 GPU_CLIENT_LOG_CODE_BLOCK({
4230 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4231 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4232 }
4233 });
4234 }
4235 helper_->SetBucketSize(kResultBucketId, 0);
4236 return success;
4237 }
4238
GetActiveUniformsiv(GLuint program,GLsizei count,const GLuint * indices,GLenum pname,GLint * params)4239 void GLES2Implementation::GetActiveUniformsiv(GLuint program,
4240 GLsizei count,
4241 const GLuint* indices,
4242 GLenum pname,
4243 GLint* params) {
4244 GPU_CLIENT_SINGLE_THREAD_CHECK();
4245 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv(" << program
4246 << ", " << count << ", "
4247 << static_cast<const void*>(indices) << ", "
4248 << GLES2Util::GetStringUniformParameter(pname) << ", "
4249 << static_cast<const void*>(params) << ")");
4250 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
4251 if (count < 0) {
4252 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
4253 return;
4254 }
4255 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
4256 this, program, count, indices, pname, params);
4257 if (success) {
4258 if (params) {
4259 GPU_CLIENT_LOG_CODE_BLOCK({
4260 for (GLsizei ii = 0; ii < count; ++ii) {
4261 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
4262 }
4263 });
4264 }
4265 }
4266 CheckGLError();
4267 }
4268
GetAttachedShaders(GLuint program,GLsizei maxcount,GLsizei * count,GLuint * shaders)4269 void GLES2Implementation::GetAttachedShaders(GLuint program,
4270 GLsizei maxcount,
4271 GLsizei* count,
4272 GLuint* shaders) {
4273 GPU_CLIENT_SINGLE_THREAD_CHECK();
4274 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders(" << program
4275 << ", " << maxcount << ", "
4276 << static_cast<const void*>(count) << ", "
4277 << static_cast<const void*>(shaders) << ", ");
4278 if (maxcount < 0) {
4279 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
4280 return;
4281 }
4282 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
4283 typedef cmds::GetAttachedShaders::Result Result;
4284 uint32_t checked_size = 0;
4285 if (!Result::ComputeSize(maxcount).AssignIfValid(&checked_size)) {
4286 SetGLError(GL_OUT_OF_MEMORY, "glGetAttachedShaders",
4287 "allocation too large");
4288 return;
4289 }
4290 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(checked_size));
4291 if (!result) {
4292 return;
4293 }
4294 result->SetNumResults(0);
4295 helper_->GetAttachedShaders(program, transfer_buffer_->GetShmId(),
4296 transfer_buffer_->GetOffset(result),
4297 checked_size);
4298 int32_t token = helper_->InsertToken();
4299 WaitForCmd();
4300 if (count) {
4301 *count = result->GetNumResults();
4302 }
4303 result->CopyResult(shaders);
4304 GPU_CLIENT_LOG_CODE_BLOCK({
4305 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4306 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4307 }
4308 });
4309 transfer_buffer_->FreePendingToken(result, token);
4310 CheckGLError();
4311 }
4312
GetShaderPrecisionFormat(GLenum shadertype,GLenum precisiontype,GLint * range,GLint * precision)4313 void GLES2Implementation::GetShaderPrecisionFormat(GLenum shadertype,
4314 GLenum precisiontype,
4315 GLint* range,
4316 GLint* precision) {
4317 GPU_CLIENT_SINGLE_THREAD_CHECK();
4318 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
4319 << GLES2Util::GetStringShaderType(shadertype) << ", "
4320 << GLES2Util::GetStringShaderPrecision(precisiontype)
4321 << ", " << static_cast<const void*>(range) << ", "
4322 << static_cast<const void*>(precision) << ", ");
4323 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
4324 typedef cmds::GetShaderPrecisionFormat::Result Result;
4325 auto result = GetResultAs<Result>();
4326 if (!result) {
4327 return;
4328 }
4329
4330 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
4331 GLStaticState::ShaderPrecisionMap::iterator i =
4332 static_state_.shader_precisions.find(key);
4333 if (i != static_state_.shader_precisions.end()) {
4334 *result = i->second;
4335 } else {
4336 result->success = false;
4337 helper_->GetShaderPrecisionFormat(shadertype, precisiontype,
4338 GetResultShmId(), result.offset());
4339 WaitForCmd();
4340 if (result->success)
4341 static_state_.shader_precisions[key] = *result;
4342 }
4343
4344 if (result->success) {
4345 if (range) {
4346 range[0] = result->min_range;
4347 range[1] = result->max_range;
4348 GPU_CLIENT_LOG(" min_range: " << range[0]);
4349 GPU_CLIENT_LOG(" min_range: " << range[1]);
4350 }
4351 if (precision) {
4352 precision[0] = result->precision;
4353 GPU_CLIENT_LOG(" min_range: " << precision[0]);
4354 }
4355 }
4356 CheckGLError();
4357 }
4358
GetStringHelper(GLenum name)4359 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
4360 if (name == GL_EXTENSIONS && cached_extension_string_) {
4361 return reinterpret_cast<const GLubyte*>(cached_extension_string_);
4362 }
4363 const char* result = nullptr;
4364 // Clears the bucket so if the command fails nothing will be in it.
4365 helper_->SetBucketSize(kResultBucketId, 0);
4366 helper_->GetString(name, kResultBucketId);
4367 std::string str;
4368 if (GetBucketAsString(kResultBucketId, &str)) {
4369 // Adds extensions implemented on client side only.
4370 if (name == GL_EXTENSIONS) {
4371 str += std::string(str.empty() ? "" : " ") +
4372 "GL_CHROMIUM_image "
4373 "GL_CHROMIUM_map_sub "
4374 "GL_CHROMIUM_ordering_barrier "
4375 "GL_CHROMIUM_sync_point "
4376 "GL_EXT_unpack_subimage";
4377 }
4378
4379 // Because of WebGL the extensions can change. We have to cache each unique
4380 // result since we don't know when the client will stop referring to a
4381 // previous one it queries.
4382 // TODO: Here we could save memory by defining RequestExtensions
4383 // invalidating the GL_EXTENSIONS string. http://crbug.com/586414
4384 const std::string& cache = *gl_strings_.insert(str).first;
4385 result = cache.c_str();
4386
4387 if (name == GL_EXTENSIONS) {
4388 cached_extension_string_ = result;
4389 std::vector<std::string> extensions =
4390 base::SplitString(cache, base::kWhitespaceASCII,
4391 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
4392 for (const std::string& extension : extensions) {
4393 cached_extensions_.push_back(
4394 gl_strings_.insert(extension).first->c_str());
4395 }
4396 }
4397 }
4398 return reinterpret_cast<const GLubyte*>(result);
4399 }
4400
GetString(GLenum name)4401 const GLubyte* GLES2Implementation::GetString(GLenum name) {
4402 GPU_CLIENT_SINGLE_THREAD_CHECK();
4403 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
4404 << GLES2Util::GetStringStringType(name) << ")");
4405 TRACE_EVENT0("gpu", "GLES2::GetString");
4406 const GLubyte* result = GetStringHelper(name);
4407 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
4408 CheckGLError();
4409 return result;
4410 }
4411
GetStringi(GLenum name,GLuint index)4412 const GLubyte* GLES2Implementation::GetStringi(GLenum name, GLuint index) {
4413 GPU_CLIENT_SINGLE_THREAD_CHECK();
4414 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetStringi("
4415 << GLES2Util::GetStringStringType(name) << "," << index
4416 << ")");
4417 TRACE_EVENT0("gpu", "GLES2::GetStringi");
4418 UpdateCachedExtensionsIfNeeded();
4419 if (name != GL_EXTENSIONS) {
4420 SetGLError(GL_INVALID_ENUM, "glGetStringi", "name");
4421 return nullptr;
4422 }
4423 if (index >= cached_extensions_.size()) {
4424 SetGLError(GL_INVALID_VALUE, "glGetStringi", "index too large");
4425 return nullptr;
4426 }
4427
4428 const char* result = cached_extensions_[index];
4429 GPU_CLIENT_LOG(" returned " << result);
4430 CheckGLError();
4431 return reinterpret_cast<const GLubyte*>(result);
4432 }
4433
GetTransformFeedbackVaryingHelper(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)4434 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(GLuint program,
4435 GLuint index,
4436 GLsizei bufsize,
4437 GLsizei* length,
4438 GLint* size,
4439 GLenum* type,
4440 char* name) {
4441 // Clear the bucket so if the command fails nothing will be in it.
4442 helper_->SetBucketSize(kResultBucketId, 0);
4443 typedef cmds::GetTransformFeedbackVarying::Result Result;
4444 auto result = GetResultAs<Result>();
4445 if (!result) {
4446 return false;
4447 }
4448 // Set as failed so if the command fails we'll recover.
4449 result->success = false;
4450 helper_->GetTransformFeedbackVarying(program, index, kResultBucketId,
4451 GetResultShmId(), result.offset());
4452 WaitForCmd();
4453 if (result->success) {
4454 if (size) {
4455 *size = result->size;
4456 }
4457 if (type) {
4458 *type = result->type;
4459 }
4460 // Note: this can invalidate |result|.
4461 GetResultNameHelper(bufsize, length, name);
4462 }
4463 return result->success != 0;
4464 }
4465
GetTransformFeedbackVarying(GLuint program,GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,char * name)4466 void GLES2Implementation::GetTransformFeedbackVarying(GLuint program,
4467 GLuint index,
4468 GLsizei bufsize,
4469 GLsizei* length,
4470 GLint* size,
4471 GLenum* type,
4472 char* name) {
4473 GPU_CLIENT_SINGLE_THREAD_CHECK();
4474 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
4475 << program << ", " << index << ", " << bufsize << ", "
4476 << static_cast<const void*>(length) << ", "
4477 << static_cast<const void*>(size) << ", "
4478 << static_cast<const void*>(type) << ", "
4479 << static_cast<const void*>(name) << ", ");
4480 if (bufsize < 0) {
4481 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
4482 "bufsize < 0");
4483 return;
4484 }
4485 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
4486 bool success =
4487 share_group_->program_info_manager()->GetTransformFeedbackVarying(
4488 this, program, index, bufsize, length, size, type, name);
4489 if (success) {
4490 if (size) {
4491 GPU_CLIENT_LOG(" size: " << *size);
4492 }
4493 if (type) {
4494 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
4495 }
4496 if (name) {
4497 GPU_CLIENT_LOG(" name: " << name);
4498 }
4499 }
4500 CheckGLError();
4501 }
4502
GetUniformfv(GLuint program,GLint location,GLfloat * params)4503 void GLES2Implementation::GetUniformfv(GLuint program,
4504 GLint location,
4505 GLfloat* params) {
4506 GPU_CLIENT_SINGLE_THREAD_CHECK();
4507 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv(" << program << ", "
4508 << location << ", " << static_cast<const void*>(params)
4509 << ")");
4510 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
4511 typedef cmds::GetUniformfv::Result Result;
4512 auto result = GetResultAs<Result>();
4513 if (!result) {
4514 return;
4515 }
4516 result->SetNumResults(0);
4517 helper_->GetUniformfv(program, location, GetResultShmId(), result.offset());
4518 WaitForCmd();
4519 result->CopyResult(params);
4520 GPU_CLIENT_LOG_CODE_BLOCK({
4521 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4522 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4523 }
4524 });
4525 CheckGLError();
4526 }
4527
GetUniformiv(GLuint program,GLint location,GLint * params)4528 void GLES2Implementation::GetUniformiv(GLuint program,
4529 GLint location,
4530 GLint* params) {
4531 GPU_CLIENT_SINGLE_THREAD_CHECK();
4532 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv(" << program << ", "
4533 << location << ", " << static_cast<const void*>(params)
4534 << ")");
4535 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
4536 typedef cmds::GetUniformiv::Result Result;
4537 auto result = GetResultAs<Result>();
4538 if (!result) {
4539 return;
4540 }
4541 result->SetNumResults(0);
4542 helper_->GetUniformiv(program, location, GetResultShmId(), result.offset());
4543 WaitForCmd();
4544 result->CopyResult(params);
4545 GPU_CLIENT_LOG_CODE_BLOCK({
4546 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4547 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4548 }
4549 });
4550 CheckGLError();
4551 }
4552
GetUniformuiv(GLuint program,GLint location,GLuint * params)4553 void GLES2Implementation::GetUniformuiv(GLuint program,
4554 GLint location,
4555 GLuint* params) {
4556 GPU_CLIENT_SINGLE_THREAD_CHECK();
4557 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv(" << program
4558 << ", " << location << ", "
4559 << static_cast<const void*>(params) << ")");
4560 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
4561 typedef cmds::GetUniformuiv::Result Result;
4562 auto result = GetResultAs<Result>();
4563 if (!result) {
4564 return;
4565 }
4566 result->SetNumResults(0);
4567 helper_->GetUniformuiv(program, location, GetResultShmId(), result.offset());
4568 WaitForCmd();
4569 result->CopyResult(params);
4570 GPU_CLIENT_LOG_CODE_BLOCK({
4571 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
4572 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4573 }
4574 });
4575 CheckGLError();
4576 }
4577
ReadPixels(GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,void * pixels)4578 void GLES2Implementation::ReadPixels(GLint xoffset,
4579 GLint yoffset,
4580 GLsizei width,
4581 GLsizei height,
4582 GLenum format,
4583 GLenum type,
4584 void* pixels) {
4585 const char* func_name = "glReadPixels";
4586 GPU_CLIENT_SINGLE_THREAD_CHECK();
4587 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels(" << xoffset << ", "
4588 << yoffset << ", " << width << ", " << height << ", "
4589 << GLES2Util::GetStringReadPixelFormat(format) << ", "
4590 << GLES2Util::GetStringPixelType(type) << ", "
4591 << static_cast<const void*>(pixels) << ")");
4592 if (width < 0 || height < 0) {
4593 SetGLError(GL_INVALID_VALUE, func_name, "dimensions < 0");
4594 return;
4595 }
4596
4597 if (pack_skip_pixels_ + width >
4598 (pack_row_length_ ? pack_row_length_ : width)) {
4599 // This is WebGL 2 specific constraints, but we do it for all ES3 contexts.
4600 SetGLError(GL_INVALID_OPERATION, func_name,
4601 "invalid pack params combination");
4602 return;
4603 }
4604
4605 // glReadPixel pads the size of each row of pixels by an amount specified by
4606 // glPixelStorei. So, we have to take that into account both in the fact that
4607 // the pixels returned from the ReadPixel command will include that padding
4608 // and that when we copy the results to the user's buffer we need to not
4609 // write those padding bytes but leave them as they are.
4610
4611 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
4612 typedef cmds::ReadPixels::Result Result;
4613
4614 uint32_t size;
4615 uint32_t unpadded_row_size;
4616 uint32_t padded_row_size;
4617 uint32_t skip_size;
4618 PixelStoreParams params;
4619 params.alignment = pack_alignment_;
4620 params.row_length = pack_row_length_;
4621 params.skip_pixels = pack_skip_pixels_;
4622 params.skip_rows = pack_skip_rows_;
4623 if (!GLES2Util::ComputeImageDataSizesES3(
4624 width, height, 1, format, type, params, &size, &unpadded_row_size,
4625 &padded_row_size, &skip_size, nullptr)) {
4626 SetGLError(GL_INVALID_VALUE, func_name, "size too large.");
4627 return;
4628 }
4629
4630 if (bound_pixel_pack_buffer_) {
4631 base::CheckedNumeric<GLuint> offset = ToGLuint(pixels);
4632 offset += skip_size;
4633 if (!offset.IsValid()) {
4634 SetGLError(GL_INVALID_VALUE, func_name, "skip size too large.");
4635 return;
4636 }
4637 helper_->ReadPixels(xoffset, yoffset, width, height, format, type, 0,
4638 offset.ValueOrDefault(0), 0, 0, false);
4639 InvalidateReadbackBufferShadowDataCHROMIUM(bound_pixel_pack_buffer_);
4640
4641 CheckGLError();
4642 return;
4643 }
4644
4645 uint32_t service_padded_row_size = 0;
4646 if (pack_row_length_ > 0 && pack_row_length_ != width) {
4647 if (!GLES2Util::ComputeImagePaddedRowSize(
4648 width, format, type, pack_alignment_, &service_padded_row_size)) {
4649 SetGLError(GL_INVALID_VALUE, func_name, "size too large.");
4650 return;
4651 }
4652 } else {
4653 service_padded_row_size = padded_row_size;
4654 }
4655
4656 if (bound_pixel_pack_transfer_buffer_id_) {
4657 if (pack_row_length_ > 0 || pack_skip_pixels_ > 0 || pack_skip_rows_ > 0) {
4658 SetGLError(GL_INVALID_OPERATION, func_name,
4659 "No ES3 pack parameters with pixel pack transfer buffer.");
4660 return;
4661 }
4662 DCHECK_EQ(0u, skip_size);
4663 GLuint offset = ToGLuint(pixels);
4664 BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid(
4665 bound_pixel_pack_transfer_buffer_id_, func_name, offset, size);
4666 if (buffer && buffer->shm_id() != -1) {
4667 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
4668 buffer->shm_id(), buffer->shm_offset() + offset, 0, 0,
4669 true);
4670 CheckGLError();
4671 }
4672 return;
4673 }
4674
4675 if (!pixels) {
4676 SetGLError(GL_INVALID_OPERATION, func_name, "pixels = NULL");
4677 return;
4678 }
4679
4680 int8_t* dest = reinterpret_cast<int8_t*>(pixels);
4681 // Advance pixels pointer past the skip rows and skip pixels
4682 dest += skip_size;
4683
4684 // Transfer by rows.
4685 // The max rows we can transfer.
4686 GLsizei remaining_rows = height;
4687 GLint y_index = yoffset;
4688 uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type);
4689 uint32_t skip_row_bytes = 0;
4690 if (xoffset < 0) {
4691 skip_row_bytes = static_cast<uint32_t>(-xoffset) * group_size;
4692 }
4693 do {
4694 // Even if height == 0, we still need to trigger the service side handling
4695 // in case invalid args are passed in and a GL errro needs to be generated.
4696 GLsizei desired_size =
4697 remaining_rows == 0 ? 0
4698 : service_padded_row_size * (remaining_rows - 1) +
4699 unpadded_row_size;
4700 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
4701 if (!buffer.valid()) {
4702 break;
4703 }
4704 GLint num_rows = ComputeNumRowsThatFitInBuffer(
4705 service_padded_row_size, unpadded_row_size, buffer.size(),
4706 remaining_rows);
4707 // NOTE: We must look up the address of the result area AFTER allocation
4708 // of the transfer buffer since the transfer buffer may be reallocated.
4709 auto result = GetResultAs<Result>();
4710 if (!result) {
4711 break;
4712 }
4713 result->success = 0; // mark as failed.
4714 result->row_length = 0;
4715 result->num_rows = 0;
4716 helper_->ReadPixels(xoffset, y_index, width, num_rows, format, type,
4717 buffer.shm_id(), buffer.offset(), GetResultShmId(),
4718 result.offset(), false);
4719 WaitForCmd();
4720 // If it was not marked as successful exit.
4721 if (!result->success) {
4722 break;
4723 }
4724 if (remaining_rows == 0) {
4725 break;
4726 }
4727 const uint8_t* src = static_cast<const uint8_t*>(buffer.address());
4728 if (padded_row_size == unpadded_row_size &&
4729 (pack_row_length_ == 0 || pack_row_length_ == width) &&
4730 result->row_length == width && result->num_rows == num_rows) {
4731 // The pixels are tightly packed.
4732 uint32_t copy_size = unpadded_row_size * num_rows;
4733 memcpy(dest, src, copy_size);
4734 dest += copy_size;
4735 } else if (result->row_length > 0 && result->num_rows > 0) {
4736 uint32_t copy_row_size = result->row_length * group_size;
4737 uint32_t copy_last_row_size = copy_row_size;
4738 if (copy_row_size + skip_row_bytes > padded_row_size) {
4739 // We need to avoid writing into next row in case the leading pixels
4740 // are out-of-bounds and they need to be left untouched.
4741 copy_row_size = padded_row_size - skip_row_bytes;
4742 }
4743 // We have to copy 1 row at a time to avoid writing padding bytes.
4744 GLint copied_rows = 0;
4745 for (GLint yy = 0; yy < num_rows; ++yy) {
4746 if (y_index + yy >= 0 && copied_rows < result->num_rows) {
4747 if (yy + 1 == num_rows && remaining_rows == num_rows) {
4748 memcpy(dest + skip_row_bytes, src + skip_row_bytes,
4749 copy_last_row_size);
4750 } else {
4751 memcpy(dest + skip_row_bytes, src + skip_row_bytes, copy_row_size);
4752 }
4753 ++copied_rows;
4754 }
4755 dest += padded_row_size;
4756 src += service_padded_row_size;
4757 }
4758 DCHECK_EQ(result->num_rows, copied_rows);
4759 }
4760 y_index += num_rows;
4761 remaining_rows -= num_rows;
4762 } while (remaining_rows);
4763 CheckGLError();
4764 }
4765
ActiveTexture(GLenum texture)4766 void GLES2Implementation::ActiveTexture(GLenum texture) {
4767 GPU_CLIENT_SINGLE_THREAD_CHECK();
4768 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
4769 << GLES2Util::GetStringEnum(texture) << ")");
4770 GLuint texture_index = texture - GL_TEXTURE0;
4771 if (texture_index >=
4772 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
4773 SetGLErrorInvalidEnum("glActiveTexture", texture, "texture");
4774 return;
4775 }
4776
4777 active_texture_unit_ = texture_index;
4778 helper_->ActiveTexture(texture);
4779 CheckGLError();
4780 }
4781
GenBuffersHelper(GLsizei,const GLuint *)4782 void GLES2Implementation::GenBuffersHelper(GLsizei /* n */,
4783 const GLuint* /* buffers */) {}
4784
GenFramebuffersHelper(GLsizei,const GLuint *)4785 void GLES2Implementation::GenFramebuffersHelper(
4786 GLsizei /* n */,
4787 const GLuint* /* framebuffers */) {}
4788
GenRenderbuffersHelper(GLsizei,const GLuint *)4789 void GLES2Implementation::GenRenderbuffersHelper(
4790 GLsizei /* n */,
4791 const GLuint* /* renderbuffers */) {}
4792
GenTexturesHelper(GLsizei,const GLuint *)4793 void GLES2Implementation::GenTexturesHelper(GLsizei /* n */,
4794 const GLuint* /* textures */) {}
4795
GenVertexArraysOESHelper(GLsizei n,const GLuint * arrays)4796 void GLES2Implementation::GenVertexArraysOESHelper(GLsizei n,
4797 const GLuint* arrays) {
4798 vertex_array_object_manager_->GenVertexArrays(n, arrays);
4799 }
4800
GenQueriesEXTHelper(GLsizei,const GLuint *)4801 void GLES2Implementation::GenQueriesEXTHelper(GLsizei /* n */,
4802 const GLuint* /* queries */) {}
4803
GenSamplersHelper(GLsizei,const GLuint *)4804 void GLES2Implementation::GenSamplersHelper(GLsizei /* n */,
4805 const GLuint* /* samplers */) {}
4806
GenTransformFeedbacksHelper(GLsizei,const GLuint *)4807 void GLES2Implementation::GenTransformFeedbacksHelper(
4808 GLsizei /* n */,
4809 const GLuint* /* transformfeedbacks */) {}
4810
4811 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
4812 // generates a new resource. On newer versions of OpenGL they don't. The code
4813 // related to binding below will need to change if we switch to the new OpenGL
4814 // model. Specifically it assumes a bind will succeed which is always true in
4815 // the old model but possibly not true in the new model if another context has
4816 // deleted the resource.
4817
4818 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
4819 // used even when Bind has failed. However, the bug is minor compared to the
4820 // overhead & duplicated checking in client side.
4821
BindBufferHelper(GLenum target,GLuint buffer_id)4822 void GLES2Implementation::BindBufferHelper(GLenum target, GLuint buffer_id) {
4823 // TODO(gman): See note #1 above.
4824 bool changed = false;
4825 switch (target) {
4826 case GL_ARRAY_BUFFER:
4827 if (bound_array_buffer_ != buffer_id) {
4828 bound_array_buffer_ = buffer_id;
4829 changed = true;
4830 }
4831 break;
4832 case GL_ATOMIC_COUNTER_BUFFER:
4833 if (bound_atomic_counter_buffer_ != buffer_id) {
4834 bound_atomic_counter_buffer_ = buffer_id;
4835 changed = true;
4836 }
4837 break;
4838 case GL_COPY_READ_BUFFER:
4839 if (bound_copy_read_buffer_ != buffer_id) {
4840 bound_copy_read_buffer_ = buffer_id;
4841 changed = true;
4842 }
4843 break;
4844 case GL_COPY_WRITE_BUFFER:
4845 if (bound_copy_write_buffer_ != buffer_id) {
4846 bound_copy_write_buffer_ = buffer_id;
4847 changed = true;
4848 }
4849 break;
4850 case GL_DISPATCH_INDIRECT_BUFFER:
4851 if (bound_dispatch_indirect_buffer_ != buffer_id) {
4852 bound_dispatch_indirect_buffer_ = buffer_id;
4853 changed = true;
4854 }
4855 break;
4856 case GL_DRAW_INDIRECT_BUFFER:
4857 if (bound_draw_indirect_buffer_ != buffer_id) {
4858 bound_draw_indirect_buffer_ = buffer_id;
4859 changed = true;
4860 }
4861 break;
4862 case GL_ELEMENT_ARRAY_BUFFER:
4863 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
4864 break;
4865 case GL_PIXEL_PACK_BUFFER:
4866 if (bound_pixel_pack_buffer_ != buffer_id) {
4867 bound_pixel_pack_buffer_ = buffer_id;
4868 changed = true;
4869 }
4870 break;
4871 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
4872 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
4873 break;
4874 case GL_PIXEL_UNPACK_BUFFER:
4875 if (bound_pixel_unpack_buffer_ != buffer_id) {
4876 bound_pixel_unpack_buffer_ = buffer_id;
4877 changed = true;
4878 }
4879 break;
4880 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
4881 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
4882 break;
4883 case GL_SHADER_STORAGE_BUFFER:
4884 if (bound_shader_storage_buffer_ != buffer_id) {
4885 bound_shader_storage_buffer_ = buffer_id;
4886 changed = true;
4887 }
4888 break;
4889 case GL_TRANSFORM_FEEDBACK_BUFFER:
4890 if (bound_transform_feedback_buffer_ != buffer_id) {
4891 bound_transform_feedback_buffer_ = buffer_id;
4892 changed = true;
4893 }
4894 break;
4895 case GL_UNIFORM_BUFFER:
4896 if (bound_uniform_buffer_ != buffer_id) {
4897 bound_uniform_buffer_ = buffer_id;
4898 changed = true;
4899 }
4900 break;
4901 default:
4902 changed = true;
4903 break;
4904 }
4905 // TODO(gman): See note #2 above.
4906 if (changed) {
4907 GetIdHandler(SharedIdNamespaces::kBuffers)
4908 ->MarkAsUsedForBind(this, target, buffer_id,
4909 &GLES2Implementation::BindBufferStub);
4910 }
4911 }
4912
BindBufferStub(GLenum target,GLuint buffer)4913 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
4914 helper_->BindBuffer(target, buffer);
4915 if (share_group_->bind_generates_resource())
4916 helper_->CommandBufferHelper::OrderingBarrier();
4917 }
4918
UpdateIndexedBufferState(GLenum target,GLuint index,GLuint buffer_id,const char * function_name)4919 bool GLES2Implementation::UpdateIndexedBufferState(GLenum target,
4920 GLuint index,
4921 GLuint buffer_id,
4922 const char* function_name) {
4923 switch (target) {
4924 case GL_ATOMIC_COUNTER_BUFFER:
4925 if (index >= static_cast<GLuint>(
4926 capabilities_.max_atomic_counter_buffer_bindings)) {
4927 SetGLError(GL_INVALID_VALUE, function_name, "index out of range");
4928 return false;
4929 }
4930 bound_atomic_counter_buffer_ = buffer_id;
4931 break;
4932 case GL_TRANSFORM_FEEDBACK_BUFFER:
4933 if (index >= static_cast<GLuint>(
4934 capabilities_.max_transform_feedback_separate_attribs)) {
4935 SetGLError(GL_INVALID_VALUE, function_name, "index out of range");
4936 return false;
4937 }
4938 bound_transform_feedback_buffer_ = buffer_id;
4939 break;
4940 case GL_SHADER_STORAGE_BUFFER:
4941 if (index >= static_cast<GLuint>(
4942 capabilities_.max_shader_storage_buffer_bindings)) {
4943 SetGLError(GL_INVALID_VALUE, function_name, "index out of range");
4944 return false;
4945 }
4946 bound_shader_storage_buffer_ = buffer_id;
4947 break;
4948 case GL_UNIFORM_BUFFER:
4949 if (index >=
4950 static_cast<GLuint>(capabilities_.max_uniform_buffer_bindings)) {
4951 SetGLError(GL_INVALID_VALUE, function_name, "index out of range");
4952 return false;
4953 }
4954 bound_uniform_buffer_ = buffer_id;
4955 break;
4956 default:
4957 SetGLError(GL_INVALID_ENUM, function_name, "invalid target");
4958 return false;
4959 }
4960 return true;
4961 }
4962
BindBufferBaseHelper(GLenum target,GLuint index,GLuint buffer_id)4963 void GLES2Implementation::BindBufferBaseHelper(GLenum target,
4964 GLuint index,
4965 GLuint buffer_id) {
4966 // TODO(zmo): See note #1 above.
4967 // TODO(zmo): See note #2 above.
4968 if (UpdateIndexedBufferState(target, index, buffer_id, "glBindBufferBase")) {
4969 GetIdHandler(SharedIdNamespaces::kBuffers)
4970 ->MarkAsUsedForBind(this, target, index, buffer_id,
4971 &GLES2Implementation::BindBufferBaseStub);
4972 }
4973 }
4974
BindBufferBaseStub(GLenum target,GLuint index,GLuint buffer)4975 void GLES2Implementation::BindBufferBaseStub(GLenum target,
4976 GLuint index,
4977 GLuint buffer) {
4978 helper_->BindBufferBase(target, index, buffer);
4979 if (share_group_->bind_generates_resource())
4980 helper_->CommandBufferHelper::Flush();
4981 }
4982
BindBufferRangeHelper(GLenum target,GLuint index,GLuint buffer_id,GLintptr offset,GLsizeiptr size)4983 void GLES2Implementation::BindBufferRangeHelper(GLenum target,
4984 GLuint index,
4985 GLuint buffer_id,
4986 GLintptr offset,
4987 GLsizeiptr size) {
4988 // TODO(zmo): See note #1 above.
4989 // TODO(zmo): See note #2 above.
4990 if (UpdateIndexedBufferState(target, index, buffer_id, "glBindBufferRange")) {
4991 GetIdHandler(SharedIdNamespaces::kBuffers)
4992 ->MarkAsUsedForBind(this, target, index, buffer_id, offset, size,
4993 &GLES2Implementation::BindBufferRangeStub);
4994 }
4995 }
4996
BindBufferRangeStub(GLenum target,GLuint index,GLuint buffer,GLintptr offset,GLsizeiptr size)4997 void GLES2Implementation::BindBufferRangeStub(GLenum target,
4998 GLuint index,
4999 GLuint buffer,
5000 GLintptr offset,
5001 GLsizeiptr size) {
5002 helper_->BindBufferRange(target, index, buffer, offset, size);
5003 if (share_group_->bind_generates_resource())
5004 helper_->CommandBufferHelper::Flush();
5005 }
5006
BindFramebufferHelper(GLenum target,GLuint framebuffer)5007 void GLES2Implementation::BindFramebufferHelper(GLenum target,
5008 GLuint framebuffer) {
5009 // TODO(gman): See note #1 above.
5010 bool changed = false;
5011 switch (target) {
5012 case GL_FRAMEBUFFER:
5013 if (bound_framebuffer_ != framebuffer ||
5014 bound_read_framebuffer_ != framebuffer) {
5015 bound_framebuffer_ = framebuffer;
5016 bound_read_framebuffer_ = framebuffer;
5017 changed = true;
5018 }
5019 break;
5020 case GL_READ_FRAMEBUFFER:
5021 DCHECK(capabilities_.major_version >= 3 ||
5022 IsChromiumFramebufferMultisampleAvailable());
5023 if (bound_read_framebuffer_ != framebuffer) {
5024 bound_read_framebuffer_ = framebuffer;
5025 changed = true;
5026 }
5027 break;
5028 case GL_DRAW_FRAMEBUFFER:
5029 DCHECK(capabilities_.major_version >= 3 ||
5030 IsChromiumFramebufferMultisampleAvailable());
5031 if (bound_framebuffer_ != framebuffer) {
5032 bound_framebuffer_ = framebuffer;
5033 changed = true;
5034 }
5035 break;
5036 default:
5037 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
5038 return;
5039 }
5040
5041 if (changed) {
5042 if (framebuffer != 0)
5043 GetIdAllocator(IdNamespaces::kFramebuffers)->MarkAsUsed(framebuffer);
5044 helper_->BindFramebuffer(target, framebuffer);
5045 }
5046 }
5047
BindRenderbufferHelper(GLenum target,GLuint renderbuffer)5048 void GLES2Implementation::BindRenderbufferHelper(GLenum target,
5049 GLuint renderbuffer) {
5050 // TODO(gman): See note #1 above.
5051 bool changed = false;
5052 switch (target) {
5053 case GL_RENDERBUFFER:
5054 if (bound_renderbuffer_ != renderbuffer) {
5055 bound_renderbuffer_ = renderbuffer;
5056 changed = true;
5057 }
5058 break;
5059 default:
5060 changed = true;
5061 break;
5062 }
5063 // TODO(zmo): See note #2 above.
5064 if (changed) {
5065 GetIdHandler(SharedIdNamespaces::kRenderbuffers)
5066 ->MarkAsUsedForBind(this, target, renderbuffer,
5067 &GLES2Implementation::BindRenderbufferStub);
5068 }
5069 }
5070
BindRenderbufferStub(GLenum target,GLuint renderbuffer)5071 void GLES2Implementation::BindRenderbufferStub(GLenum target,
5072 GLuint renderbuffer) {
5073 helper_->BindRenderbuffer(target, renderbuffer);
5074 if (share_group_->bind_generates_resource())
5075 helper_->CommandBufferHelper::OrderingBarrier();
5076 }
5077
BindSamplerHelper(GLuint unit,GLuint sampler)5078 void GLES2Implementation::BindSamplerHelper(GLuint unit, GLuint sampler) {
5079 helper_->BindSampler(unit, sampler);
5080 }
5081
BindTextureHelper(GLenum target,GLuint texture)5082 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
5083 // TODO(gman): See note #1 above.
5084 bool changed = false;
5085 TextureUnit& unit = texture_units_[active_texture_unit_];
5086 switch (target) {
5087 case GL_TEXTURE_2D:
5088 if (unit.bound_texture_2d != texture) {
5089 unit.bound_texture_2d = texture;
5090 changed = true;
5091 }
5092 break;
5093 case GL_TEXTURE_CUBE_MAP:
5094 if (unit.bound_texture_cube_map != texture) {
5095 unit.bound_texture_cube_map = texture;
5096 changed = true;
5097 }
5098 break;
5099 case GL_TEXTURE_EXTERNAL_OES:
5100 if (unit.bound_texture_external_oes != texture) {
5101 unit.bound_texture_external_oes = texture;
5102 changed = true;
5103 }
5104 break;
5105 case GL_TEXTURE_RECTANGLE_ARB:
5106 if (unit.bound_texture_rectangle_arb != texture) {
5107 unit.bound_texture_rectangle_arb = texture;
5108 changed = true;
5109 }
5110 break;
5111 default:
5112 changed = true;
5113 break;
5114 }
5115 // TODO(gman): See note #2 above.
5116 if (changed) {
5117 GetIdHandler(SharedIdNamespaces::kTextures)
5118 ->MarkAsUsedForBind(this, target, texture,
5119 &GLES2Implementation::BindTextureStub);
5120 }
5121 }
5122
BindTextureStub(GLenum target,GLuint texture)5123 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
5124 helper_->BindTexture(target, texture);
5125 if (share_group_->bind_generates_resource())
5126 helper_->CommandBufferHelper::OrderingBarrier();
5127 }
5128
BindTransformFeedbackHelper(GLenum target,GLuint transformfeedback)5129 void GLES2Implementation::BindTransformFeedbackHelper(
5130 GLenum target,
5131 GLuint transformfeedback) {
5132 helper_->BindTransformFeedback(target, transformfeedback);
5133 }
5134
BindVertexArrayOESHelper(GLuint array)5135 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
5136 bool changed = false;
5137 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
5138 if (changed) {
5139 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
5140 // because unlike other resources VertexArrayObject ids must
5141 // be generated by GenVertexArrays. A random id to Bind will not
5142 // generate a new object.
5143 helper_->BindVertexArrayOES(array);
5144 }
5145 } else {
5146 SetGLError(GL_INVALID_OPERATION, "glBindVertexArrayOES",
5147 "id was not generated with glGenVertexArrayOES");
5148 }
5149 }
5150
UseProgramHelper(GLuint program)5151 void GLES2Implementation::UseProgramHelper(GLuint program) {
5152 if (current_program_ != program) {
5153 current_program_ = program;
5154 helper_->UseProgram(program);
5155 }
5156 }
5157
IsBufferReservedId(GLuint id)5158 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
5159 return vertex_array_object_manager_->IsReservedId(id);
5160 }
5161
DeleteBuffersHelper(GLsizei n,const GLuint * buffers)5162 void GLES2Implementation::DeleteBuffersHelper(GLsizei n,
5163 const GLuint* buffers) {
5164 if (!GetIdHandler(SharedIdNamespaces::kBuffers)
5165 ->FreeIds(this, n, buffers,
5166 &GLES2Implementation::DeleteBuffersStub)) {
5167 SetGLError(GL_INVALID_VALUE, "glDeleteBuffers",
5168 "id not created by this context.");
5169 return;
5170 }
5171 for (GLsizei ii = 0; ii < n; ++ii) {
5172 if (buffers[ii] == bound_array_buffer_) {
5173 bound_array_buffer_ = 0;
5174 }
5175 if (buffers[ii] == bound_atomic_counter_buffer_) {
5176 bound_atomic_counter_buffer_ = 0;
5177 }
5178 if (buffers[ii] == bound_copy_read_buffer_) {
5179 bound_copy_read_buffer_ = 0;
5180 }
5181 if (buffers[ii] == bound_copy_write_buffer_) {
5182 bound_copy_write_buffer_ = 0;
5183 }
5184 if (buffers[ii] == bound_dispatch_indirect_buffer_) {
5185 bound_dispatch_indirect_buffer_ = 0;
5186 }
5187 if (buffers[ii] == bound_draw_indirect_buffer_) {
5188 bound_draw_indirect_buffer_ = 0;
5189 }
5190 if (buffers[ii] == bound_pixel_pack_buffer_) {
5191 bound_pixel_pack_buffer_ = 0;
5192 }
5193 if (buffers[ii] == bound_pixel_unpack_buffer_) {
5194 bound_pixel_unpack_buffer_ = 0;
5195 }
5196 if (buffers[ii] == bound_shader_storage_buffer_) {
5197 bound_shader_storage_buffer_ = 0;
5198 }
5199 if (buffers[ii] == bound_transform_feedback_buffer_) {
5200 bound_transform_feedback_buffer_ = 0;
5201 }
5202 if (buffers[ii] == bound_uniform_buffer_) {
5203 bound_uniform_buffer_ = 0;
5204 }
5205 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
5206
5207 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
5208 if (buffer)
5209 RemoveTransferBuffer(buffer);
5210
5211 readback_buffer_shadow_tracker_->RemoveBuffer(buffers[ii]);
5212
5213 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
5214 bound_pixel_unpack_transfer_buffer_id_ = 0;
5215 }
5216
5217 RemoveMappedBufferRangeById(buffers[ii]);
5218 }
5219 }
5220
DeleteBuffersStub(GLsizei n,const GLuint * buffers)5221 void GLES2Implementation::DeleteBuffersStub(GLsizei n, const GLuint* buffers) {
5222 helper_->DeleteBuffersImmediate(n, buffers);
5223 }
5224
DeleteFramebuffersHelper(GLsizei n,const GLuint * framebuffers)5225 void GLES2Implementation::DeleteFramebuffersHelper(GLsizei n,
5226 const GLuint* framebuffers) {
5227 helper_->DeleteFramebuffersImmediate(n, framebuffers);
5228 IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::kFramebuffers);
5229 for (GLsizei ii = 0; ii < n; ++ii) {
5230 id_allocator->FreeID(framebuffers[ii]);
5231 if (framebuffers[ii] == bound_framebuffer_) {
5232 bound_framebuffer_ = 0;
5233 }
5234 if (framebuffers[ii] == bound_read_framebuffer_) {
5235 bound_read_framebuffer_ = 0;
5236 }
5237 }
5238 }
5239
DeleteRenderbuffersHelper(GLsizei n,const GLuint * renderbuffers)5240 void GLES2Implementation::DeleteRenderbuffersHelper(
5241 GLsizei n,
5242 const GLuint* renderbuffers) {
5243 if (!GetIdHandler(SharedIdNamespaces::kRenderbuffers)
5244 ->FreeIds(this, n, renderbuffers,
5245 &GLES2Implementation::DeleteRenderbuffersStub)) {
5246 SetGLError(GL_INVALID_VALUE, "glDeleteRenderbuffers",
5247 "id not created by this context.");
5248 return;
5249 }
5250 for (GLsizei ii = 0; ii < n; ++ii) {
5251 if (renderbuffers[ii] == bound_renderbuffer_) {
5252 bound_renderbuffer_ = 0;
5253 }
5254 }
5255 }
5256
DeleteRenderbuffersStub(GLsizei n,const GLuint * renderbuffers)5257 void GLES2Implementation::DeleteRenderbuffersStub(GLsizei n,
5258 const GLuint* renderbuffers) {
5259 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
5260 }
5261
DeleteTexturesHelper(GLsizei n,const GLuint * textures)5262 void GLES2Implementation::DeleteTexturesHelper(GLsizei n,
5263 const GLuint* textures) {
5264 if (!GetIdHandler(SharedIdNamespaces::kTextures)
5265 ->FreeIds(this, n, textures,
5266 &GLES2Implementation::DeleteTexturesStub)) {
5267 SetGLError(GL_INVALID_VALUE, "glDeleteTextures",
5268 "id not created by this context.");
5269 return;
5270 }
5271 for (GLsizei ii = 0; ii < n; ++ii) {
5272 share_group_->discardable_texture_manager()->FreeTexture(textures[ii]);
5273 }
5274 UnbindTexturesHelper(n, textures);
5275 }
5276
UnbindTexturesHelper(GLsizei n,const GLuint * textures)5277 void GLES2Implementation::UnbindTexturesHelper(GLsizei n,
5278 const GLuint* textures) {
5279 for (GLsizei ii = 0; ii < n; ++ii) {
5280 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
5281 ++tt) {
5282 TextureUnit& unit = texture_units_[tt];
5283 if (textures[ii] == unit.bound_texture_2d) {
5284 unit.bound_texture_2d = 0;
5285 }
5286 if (textures[ii] == unit.bound_texture_cube_map) {
5287 unit.bound_texture_cube_map = 0;
5288 }
5289 if (textures[ii] == unit.bound_texture_external_oes) {
5290 unit.bound_texture_external_oes = 0;
5291 }
5292 if (textures[ii] == unit.bound_texture_rectangle_arb) {
5293 unit.bound_texture_rectangle_arb = 0;
5294 }
5295 }
5296 }
5297 }
5298
DeleteTexturesStub(GLsizei n,const GLuint * textures)5299 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
5300 const GLuint* textures) {
5301 helper_->DeleteTexturesImmediate(n, textures);
5302 }
5303
DeleteVertexArraysOESHelper(GLsizei n,const GLuint * arrays)5304 void GLES2Implementation::DeleteVertexArraysOESHelper(GLsizei n,
5305 const GLuint* arrays) {
5306 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
5307 helper_->DeleteVertexArraysOESImmediate(n, arrays);
5308 IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::kVertexArrays);
5309 for (GLsizei ii = 0; ii < n; ++ii)
5310 id_allocator->FreeID(arrays[ii]);
5311 }
5312
DeleteSamplersStub(GLsizei n,const GLuint * samplers)5313 void GLES2Implementation::DeleteSamplersStub(GLsizei n,
5314 const GLuint* samplers) {
5315 helper_->DeleteSamplersImmediate(n, samplers);
5316 }
5317
DeleteSamplersHelper(GLsizei n,const GLuint * samplers)5318 void GLES2Implementation::DeleteSamplersHelper(GLsizei n,
5319 const GLuint* samplers) {
5320 if (!GetIdHandler(SharedIdNamespaces::kSamplers)
5321 ->FreeIds(this, n, samplers,
5322 &GLES2Implementation::DeleteSamplersStub)) {
5323 SetGLError(GL_INVALID_VALUE, "glDeleteSamplers",
5324 "id not created by this context.");
5325 return;
5326 }
5327 }
5328
DeleteTransformFeedbacksHelper(GLsizei n,const GLuint * transformfeedbacks)5329 void GLES2Implementation::DeleteTransformFeedbacksHelper(
5330 GLsizei n,
5331 const GLuint* transformfeedbacks) {
5332 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
5333 IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::kTransformFeedbacks);
5334 for (GLsizei ii = 0; ii < n; ++ii)
5335 id_allocator->FreeID(transformfeedbacks[ii]);
5336 }
5337
DisableVertexAttribArray(GLuint index)5338 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
5339 GPU_CLIENT_SINGLE_THREAD_CHECK();
5340 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisableVertexAttribArray("
5341 << index << ")");
5342 vertex_array_object_manager_->SetAttribEnable(index, false);
5343 helper_->DisableVertexAttribArray(index);
5344 CheckGLError();
5345 }
5346
EnableVertexAttribArray(GLuint index)5347 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
5348 GPU_CLIENT_SINGLE_THREAD_CHECK();
5349 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
5350 << index << ")");
5351 vertex_array_object_manager_->SetAttribEnable(index, true);
5352 helper_->EnableVertexAttribArray(index);
5353 CheckGLError();
5354 }
5355
DrawArrays(GLenum mode,GLint first,GLsizei count)5356 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
5357 GPU_CLIENT_SINGLE_THREAD_CHECK();
5358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
5359 << GLES2Util::GetStringDrawMode(mode) << ", " << first
5360 << ", " << count << ")");
5361 if (count < 0) {
5362 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
5363 return;
5364 }
5365 bool simulated = false;
5366 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
5367 GLsizei num_elements;
5368 if (!base::CheckAdd(first, count).AssignIfValid(&num_elements)) {
5369 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "first+count overflow");
5370 return;
5371 }
5372 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
5373 "glDrawArrays", this, helper_, num_elements, 0, &simulated)) {
5374 return;
5375 }
5376 }
5377 helper_->DrawArrays(mode, first, count);
5378 RestoreArrayBuffer(simulated);
5379 CheckGLError();
5380 }
5381
DrawArraysIndirect(GLenum mode,const void * offset)5382 void GLES2Implementation::DrawArraysIndirect(GLenum mode, const void* offset) {
5383 GPU_CLIENT_SINGLE_THREAD_CHECK();
5384 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysIndirect("
5385 << GLES2Util::GetStringDrawMode(mode) << ", " << offset
5386 << ")");
5387 if (!ValidateOffset("glDrawArraysIndirect",
5388 reinterpret_cast<GLintptr>(offset))) {
5389 return;
5390 }
5391 // This is for WebGL 2.0 Compute which doesn't support client side arrays
5392 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
5393 SetGLError(GL_INVALID_OPERATION, "glDrawArraysIndirect",
5394 "Missing array buffer for vertex attribute");
5395 return;
5396 }
5397 helper_->DrawArraysIndirect(mode, ToGLuint(offset));
5398 CheckGLError();
5399 }
5400
GetVertexAttribfv(GLuint index,GLenum pname,GLfloat * params)5401 void GLES2Implementation::GetVertexAttribfv(GLuint index,
5402 GLenum pname,
5403 GLfloat* params) {
5404 GPU_CLIENT_SINGLE_THREAD_CHECK();
5405 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv(" << index
5406 << ", " << GLES2Util::GetStringVertexAttribute(pname)
5407 << ", " << static_cast<const void*>(params) << ")");
5408 uint32_t value = 0;
5409 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
5410 *params = static_cast<GLfloat>(value);
5411 return;
5412 }
5413 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
5414 typedef cmds::GetVertexAttribfv::Result Result;
5415 auto result = GetResultAs<Result>();
5416 if (!result) {
5417 return;
5418 }
5419 result->SetNumResults(0);
5420 helper_->GetVertexAttribfv(index, pname, GetResultShmId(), result.offset());
5421 WaitForCmd();
5422 result->CopyResult(params);
5423 GPU_CLIENT_LOG_CODE_BLOCK({
5424 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5425 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5426 }
5427 });
5428 CheckGLError();
5429 }
5430
GetVertexAttribiv(GLuint index,GLenum pname,GLint * params)5431 void GLES2Implementation::GetVertexAttribiv(GLuint index,
5432 GLenum pname,
5433 GLint* params) {
5434 GPU_CLIENT_SINGLE_THREAD_CHECK();
5435 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv(" << index
5436 << ", " << GLES2Util::GetStringVertexAttribute(pname)
5437 << ", " << static_cast<const void*>(params) << ")");
5438 uint32_t value = 0;
5439 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
5440 *params = static_cast<GLint>(value);
5441 return;
5442 }
5443 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
5444 typedef cmds::GetVertexAttribiv::Result Result;
5445 auto result = GetResultAs<Result>();
5446 if (!result) {
5447 return;
5448 }
5449 result->SetNumResults(0);
5450 helper_->GetVertexAttribiv(index, pname, GetResultShmId(), result.offset());
5451 WaitForCmd();
5452 result->CopyResult(params);
5453 GPU_CLIENT_LOG_CODE_BLOCK({
5454 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5455 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5456 }
5457 });
5458 CheckGLError();
5459 }
5460
GetVertexAttribIiv(GLuint index,GLenum pname,GLint * params)5461 void GLES2Implementation::GetVertexAttribIiv(GLuint index,
5462 GLenum pname,
5463 GLint* params) {
5464 GPU_CLIENT_SINGLE_THREAD_CHECK();
5465 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv(" << index
5466 << ", " << GLES2Util::GetStringVertexAttribute(pname)
5467 << ", " << static_cast<const void*>(params) << ")");
5468 uint32_t value = 0;
5469 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
5470 *params = static_cast<GLint>(value);
5471 return;
5472 }
5473 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
5474 typedef cmds::GetVertexAttribiv::Result Result;
5475 auto result = GetResultAs<Result>();
5476 if (!result) {
5477 return;
5478 }
5479 result->SetNumResults(0);
5480 helper_->GetVertexAttribIiv(index, pname, GetResultShmId(), result.offset());
5481 WaitForCmd();
5482 result->CopyResult(params);
5483 GPU_CLIENT_LOG_CODE_BLOCK({
5484 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5485 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5486 }
5487 });
5488 CheckGLError();
5489 }
5490
GetVertexAttribIuiv(GLuint index,GLenum pname,GLuint * params)5491 void GLES2Implementation::GetVertexAttribIuiv(GLuint index,
5492 GLenum pname,
5493 GLuint* params) {
5494 GPU_CLIENT_SINGLE_THREAD_CHECK();
5495 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv(" << index
5496 << ", " << GLES2Util::GetStringVertexAttribute(pname)
5497 << ", " << static_cast<const void*>(params) << ")");
5498 uint32_t value = 0;
5499 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
5500 *params = static_cast<GLuint>(value);
5501 return;
5502 }
5503 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
5504 typedef cmds::GetVertexAttribiv::Result Result;
5505 auto result = GetResultAs<Result>();
5506 if (!result) {
5507 return;
5508 }
5509 result->SetNumResults(0);
5510 helper_->GetVertexAttribIuiv(index, pname, GetResultShmId(), result.offset());
5511 WaitForCmd();
5512 result->CopyResult(params);
5513 GPU_CLIENT_LOG_CODE_BLOCK({
5514 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5515 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5516 }
5517 });
5518 CheckGLError();
5519 }
5520
GetGraphicsResetStatusKHR()5521 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
5522 GPU_CLIENT_SINGLE_THREAD_CHECK();
5523 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
5524 // If any context (including ourselves) has seen itself become lost,
5525 // then it will have told the ShareGroup, so just report its status.
5526 if (share_group_->IsLost())
5527 return GL_UNKNOWN_CONTEXT_RESET_KHR;
5528 return GL_NO_ERROR;
5529 }
5530
Swap(uint32_t flags,SwapCompletedCallback complete_callback,PresentationCallback presentation_callback)5531 void GLES2Implementation::Swap(uint32_t flags,
5532 SwapCompletedCallback complete_callback,
5533 PresentationCallback presentation_callback) {
5534 SwapBuffers(PrepareNextSwapId(std::move(complete_callback),
5535 std::move(presentation_callback)),
5536 flags);
5537 }
5538
SwapWithBounds(const std::vector<gfx::Rect> & rects,uint32_t flags,SwapCompletedCallback swap_completed,PresentationCallback presentation_callback)5539 void GLES2Implementation::SwapWithBounds(
5540 const std::vector<gfx::Rect>& rects,
5541 uint32_t flags,
5542 SwapCompletedCallback swap_completed,
5543 PresentationCallback presentation_callback) {
5544 std::vector<int> rects_data(rects.size() * 4);
5545 for (size_t i = 0; i < rects.size(); ++i) {
5546 rects_data[i * 4 + 0] = rects[i].x();
5547 rects_data[i * 4 + 1] = rects[i].y();
5548 rects_data[i * 4 + 2] = rects[i].width();
5549 rects_data[i * 4 + 3] = rects[i].height();
5550 }
5551 SwapBuffersWithBoundsCHROMIUM(
5552 PrepareNextSwapId(std::move(swap_completed),
5553 std::move(presentation_callback)),
5554 rects.size(), rects_data.data(), flags);
5555 }
5556
PartialSwapBuffers(const gfx::Rect & sub_buffer,uint32_t flags,SwapCompletedCallback swap_completed,PresentationCallback presentation_callback)5557 void GLES2Implementation::PartialSwapBuffers(
5558 const gfx::Rect& sub_buffer,
5559 uint32_t flags,
5560 SwapCompletedCallback swap_completed,
5561 PresentationCallback presentation_callback) {
5562 PostSubBufferCHROMIUM(PrepareNextSwapId(std::move(swap_completed),
5563 std::move(presentation_callback)),
5564 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(),
5565 sub_buffer.height(), flags);
5566 }
5567
CommitOverlayPlanes(uint32_t flags,SwapCompletedCallback swap_completed,PresentationCallback presentation_callback)5568 void GLES2Implementation::CommitOverlayPlanes(
5569 uint32_t flags,
5570 SwapCompletedCallback swap_completed,
5571 PresentationCallback presentation_callback) {
5572 CommitOverlayPlanesCHROMIUM(
5573 PrepareNextSwapId(std::move(swap_completed),
5574 std::move(presentation_callback)),
5575 flags);
5576 }
5577
GetGLESOverlayTransform(gfx::OverlayTransform plane_transform)5578 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
5579 switch (plane_transform) {
5580 case gfx::OVERLAY_TRANSFORM_INVALID:
5581 break;
5582 case gfx::OVERLAY_TRANSFORM_NONE:
5583 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
5584 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
5585 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
5586 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
5587 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
5588 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
5589 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
5590 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
5591 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
5592 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
5593 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
5594 }
5595 NOTREACHED();
5596 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
5597 }
5598
ScheduleOverlayPlane(int plane_z_order,gfx::OverlayTransform plane_transform,unsigned overlay_texture_id,const gfx::Rect & display_bounds,const gfx::RectF & uv_rect,bool enable_blend,unsigned gpu_fence_id)5599 void GLES2Implementation::ScheduleOverlayPlane(
5600 int plane_z_order,
5601 gfx::OverlayTransform plane_transform,
5602 unsigned overlay_texture_id,
5603 const gfx::Rect& display_bounds,
5604 const gfx::RectF& uv_rect,
5605 bool enable_blend,
5606 unsigned gpu_fence_id) {
5607 ScheduleOverlayPlaneCHROMIUM(
5608 plane_z_order, GetGLESOverlayTransform(plane_transform),
5609 overlay_texture_id, display_bounds.x(), display_bounds.y(),
5610 display_bounds.width(), display_bounds.height(), uv_rect.x(), uv_rect.y(),
5611 uv_rect.width(), uv_rect.height(), enable_blend, gpu_fence_id);
5612 }
5613
ScheduleCALayerSharedStateCHROMIUM(GLfloat opacity,GLboolean is_clipped,const GLfloat * clip_rect,const GLfloat * rounded_corner_bounds,GLint sorting_context_id,const GLfloat * transform)5614 void GLES2Implementation::ScheduleCALayerSharedStateCHROMIUM(
5615 GLfloat opacity,
5616 GLboolean is_clipped,
5617 const GLfloat* clip_rect,
5618 const GLfloat* rounded_corner_bounds,
5619 GLint sorting_context_id,
5620 const GLfloat* transform) {
5621 // 4 for clip_rect, 5 for rounded_corner_rect, 16 for transform.
5622 uint32_t shm_size = 25 * sizeof(GLfloat);
5623 ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_);
5624 if (!buffer.valid() || buffer.size() < shm_size) {
5625 SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerSharedStateCHROMIUM",
5626 "out of memory");
5627 return;
5628 }
5629 GLfloat* mem = static_cast<GLfloat*>(buffer.address());
5630 memcpy(mem + 0, clip_rect, 4 * sizeof(GLfloat));
5631 memcpy(mem + 4, rounded_corner_bounds, 5 * sizeof(GLfloat));
5632 memcpy(mem + 9, transform, 16 * sizeof(GLfloat));
5633 helper_->ScheduleCALayerSharedStateCHROMIUM(opacity, is_clipped,
5634 sorting_context_id,
5635 buffer.shm_id(), buffer.offset());
5636 }
5637
ScheduleCALayerCHROMIUM(GLuint contents_texture_id,const GLfloat * contents_rect,GLuint background_color,GLuint edge_aa_mask,const GLfloat * bounds_rect,GLuint filter)5638 void GLES2Implementation::ScheduleCALayerCHROMIUM(GLuint contents_texture_id,
5639 const GLfloat* contents_rect,
5640 GLuint background_color,
5641 GLuint edge_aa_mask,
5642 const GLfloat* bounds_rect,
5643 GLuint filter) {
5644 uint32_t shm_size = 8 * sizeof(GLfloat);
5645 ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_);
5646 if (!buffer.valid() || buffer.size() < shm_size) {
5647 SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerCHROMIUM",
5648 "out of memory");
5649 return;
5650 }
5651 GLfloat* mem = static_cast<GLfloat*>(buffer.address());
5652 memcpy(mem + 0, contents_rect, 4 * sizeof(GLfloat));
5653 memcpy(mem + 4, bounds_rect, 4 * sizeof(GLfloat));
5654 helper_->ScheduleCALayerCHROMIUM(contents_texture_id, background_color,
5655 edge_aa_mask, filter, buffer.shm_id(),
5656 buffer.offset());
5657 }
5658
SetColorSpaceMetadataCHROMIUM(GLuint texture_id,GLcolorSpace color_space)5659 void GLES2Implementation::SetColorSpaceMetadataCHROMIUM(
5660 GLuint texture_id,
5661 GLcolorSpace color_space) {
5662 #if defined(__native_client__)
5663 // Including gfx::ColorSpace would bring Skia and a lot of other code into
5664 // NaCl's IRT.
5665 SetGLError(GL_INVALID_VALUE, "GLES2::SetColorSpaceMetadataCHROMIUM",
5666 "not supported");
5667 #else
5668 gfx::ColorSpace gfx_color_space;
5669 if (color_space)
5670 gfx_color_space = *reinterpret_cast<const gfx::ColorSpace*>(color_space);
5671 base::Pickle color_space_data;
5672 IPC::ParamTraits<gfx::ColorSpace>::Write(&color_space_data, gfx_color_space);
5673 ScopedTransferBufferPtr buffer(color_space_data.size(), helper_,
5674 transfer_buffer_);
5675 if (!buffer.valid() || buffer.size() < color_space_data.size()) {
5676 SetGLError(GL_OUT_OF_MEMORY, "GLES2::SetColorSpaceMetadataCHROMIUM",
5677 "out of memory");
5678 return;
5679 }
5680 memcpy(buffer.address(), color_space_data.data(), color_space_data.size());
5681 helper_->SetColorSpaceMetadataCHROMIUM(
5682 texture_id, buffer.shm_id(), buffer.offset(), color_space_data.size());
5683 #endif
5684 }
5685
CommitOverlayPlanesCHROMIUM(uint64_t swap_id,uint32_t flags)5686 void GLES2Implementation::CommitOverlayPlanesCHROMIUM(uint64_t swap_id,
5687 uint32_t flags) {
5688 GPU_CLIENT_SINGLE_THREAD_CHECK();
5689 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CommitOverlayPlanesCHROMIUM()");
5690 TRACE_EVENT0("gpu", "GLES2::CommitOverlayPlanesCHROMIUM");
5691
5692 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
5693 swap_buffers_tokens_.push(helper_->InsertToken());
5694 helper_->CommitOverlayPlanesCHROMIUM(swap_id, flags);
5695 helper_->CommandBufferHelper::Flush();
5696 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
5697 helper_->WaitForToken(swap_buffers_tokens_.front());
5698 swap_buffers_tokens_.pop();
5699 }
5700 }
5701
EnableFeatureCHROMIUM(const char * feature)5702 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(const char* feature) {
5703 GPU_CLIENT_SINGLE_THREAD_CHECK();
5704 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
5705 << feature << ")");
5706 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
5707 typedef cmds::EnableFeatureCHROMIUM::Result Result;
5708 SetBucketAsCString(kResultBucketId, feature);
5709 auto result = GetResultAs<Result>();
5710 if (!result) {
5711 return false;
5712 }
5713 *result = 0;
5714 helper_->EnableFeatureCHROMIUM(kResultBucketId, GetResultShmId(),
5715 result.offset());
5716 WaitForCmd();
5717 helper_->SetBucketSize(kResultBucketId, 0);
5718 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
5719 return *result != 0;
5720 }
5721
MapBufferSubDataCHROMIUM(GLuint target,GLintptr offset,GLsizeiptr size,GLenum access)5722 void* GLES2Implementation::MapBufferSubDataCHROMIUM(GLuint target,
5723 GLintptr offset,
5724 GLsizeiptr size,
5725 GLenum access) {
5726 GPU_CLIENT_SINGLE_THREAD_CHECK();
5727 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
5728 << target << ", " << offset << ", " << size << ", "
5729 << GLES2Util::GetStringEnum(access) << ")");
5730 // NOTE: target is NOT checked because the service will check it
5731 // and we don't know what targets are valid.
5732 if (access != GL_WRITE_ONLY) {
5733 SetGLErrorInvalidEnum("glMapBufferSubDataCHROMIUM", access, "access");
5734 return nullptr;
5735 }
5736 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
5737 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
5738 return nullptr;
5739 }
5740
5741 int32_t shm_id;
5742 unsigned int shm_offset;
5743 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
5744 if (!mem) {
5745 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
5746 return nullptr;
5747 }
5748
5749 std::pair<MappedBufferMap::iterator, bool> result = mapped_buffers_.insert(
5750 std::make_pair(mem, MappedBuffer(access, shm_id, mem, shm_offset, target,
5751 offset, size)));
5752 DCHECK(result.second);
5753 GPU_CLIENT_LOG(" returned " << mem);
5754 return mem;
5755 }
5756
UnmapBufferSubDataCHROMIUM(const void * mem)5757 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
5758 GPU_CLIENT_SINGLE_THREAD_CHECK();
5759 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM("
5760 << mem << ")");
5761 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
5762 if (it == mapped_buffers_.end()) {
5763 SetGLError(GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM",
5764 "buffer not mapped");
5765 return;
5766 }
5767 const MappedBuffer& mb = it->second;
5768 helper_->BufferSubData(mb.target, mb.offset, mb.size, mb.shm_id,
5769 mb.shm_offset);
5770 InvalidateReadbackBufferShadowDataCHROMIUM(GetBoundBufferHelper(mb.target));
5771 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
5772 mapped_buffers_.erase(it);
5773 CheckGLError();
5774 }
5775
GetBoundBufferHelper(GLenum target)5776 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
5777 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
5778 GLint id = 0;
5779 bool cached = GetHelper(binding, &id);
5780 DCHECK(cached);
5781 return static_cast<GLuint>(id);
5782 }
5783
RemoveMappedBufferRangeByTarget(GLenum target)5784 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
5785 GLuint buffer = GetBoundBufferHelper(target);
5786 RemoveMappedBufferRangeById(buffer);
5787 }
5788
RemoveMappedBufferRangeById(GLuint buffer)5789 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
5790 if (buffer > 0) {
5791 auto iter = mapped_buffer_range_map_.find(buffer);
5792 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
5793 mapped_memory_->FreePendingToken(iter->second.shm_memory,
5794 helper_->InsertToken());
5795 mapped_buffer_range_map_.erase(iter);
5796 }
5797 }
5798 }
5799
ClearMappedBufferRangeMap()5800 void GLES2Implementation::ClearMappedBufferRangeMap() {
5801 for (auto& buffer_range : mapped_buffer_range_map_) {
5802 if (buffer_range.second.shm_memory) {
5803 mapped_memory_->FreePendingToken(buffer_range.second.shm_memory,
5804 helper_->InsertToken());
5805 }
5806 }
5807 mapped_buffer_range_map_.clear();
5808 }
5809
MapBufferRange(GLenum target,GLintptr offset,GLsizeiptr size,GLbitfield access)5810 void* GLES2Implementation::MapBufferRange(GLenum target,
5811 GLintptr offset,
5812 GLsizeiptr size,
5813 GLbitfield access) {
5814 GPU_CLIENT_SINGLE_THREAD_CHECK();
5815 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
5816 << GLES2Util::GetStringEnum(target) << ", " << offset
5817 << ", " << size << ", " << access << ")");
5818 if (!ValidateSize("glMapBufferRange", size) ||
5819 !ValidateOffset("glMapBufferRange", offset)) {
5820 return nullptr;
5821 }
5822
5823 GLuint buffer = GetBoundBufferHelper(target);
5824
5825 void* mem = nullptr;
5826
5827 // Early return if we have a valid shadow copy for readback
5828 if (access == GL_MAP_READ_BIT) {
5829 // This will return an incorrect result if the client does the following:
5830 // * Writes into a buffer
5831 // * Issues query (GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM)
5832 // * Writes into the buffer using transform feedback (but doesn't issue
5833 // InvalidateReadbackBufferShadowDataCHROMIUM correctly)
5834 // * Waits on the query
5835 // * Reads from the buffer (may return results from before the transfom
5836 // feedback operation).
5837 // Therefore, if (and only if) a client uses the
5838 // GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM query, it must also correctly
5839 // use InvalidateReadbackBufferShadowDataCHROMIUM. WebGL (at the time of
5840 // this writing) is expected to be the only client which uses
5841 // GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM.
5842 if (auto* buffer_object =
5843 readback_buffer_shadow_tracker_->GetBuffer(buffer)) {
5844 mem = buffer_object->MapReadbackShm(offset, size);
5845 if (!mem) {
5846 // (If there's no valid shadow copy, warn and fall back to usual logic.)
5847 SendErrorMessage(
5848 "performance warning: READ-usage buffer was read back without "
5849 "waiting on a fence. This caused a graphics pipeline stall.",
5850 0);
5851 }
5852 }
5853 }
5854
5855 // Usual, round-trip path if we're not doing a shadow-copy readback
5856 int32_t shm_id = 0;
5857 unsigned int shm_offset = 0;
5858 if (!mem) {
5859 mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
5860 if (!mem) {
5861 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
5862 return nullptr;
5863 }
5864
5865 typedef cmds::MapBufferRange::Result Result;
5866 auto result = GetResultAs<Result>();
5867 *result = 0;
5868 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
5869 GetResultShmId(), result.offset());
5870 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
5871 // consider an early return without WaitForCmd(). crbug.com/465804.
5872 WaitForCmd();
5873 if (*result) {
5874 const GLbitfield kInvalidateBits =
5875 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
5876 if ((access & kInvalidateBits) != 0) {
5877 // We do not read back from the buffer, therefore, we set the client
5878 // side memory to zero to avoid uninitialized data.
5879 memset(mem, 0, size);
5880 }
5881 } else {
5882 mapped_memory_->Free(mem);
5883 mem = nullptr;
5884 }
5885 }
5886
5887 // Track this mapping regardless of which path was taken above.
5888 if (mem) {
5889 DCHECK_NE(0u, buffer);
5890 // glMapBufferRange fails on an already mapped buffer.
5891 DCHECK(mapped_buffer_range_map_.find(buffer) ==
5892 mapped_buffer_range_map_.end());
5893 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
5894 buffer,
5895 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
5896 DCHECK(iter.second);
5897 }
5898
5899 GPU_CLIENT_LOG(" returned " << mem);
5900 CheckGLError();
5901 return mem;
5902 }
5903
UnmapBuffer(GLenum target)5904 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
5905 GPU_CLIENT_SINGLE_THREAD_CHECK();
5906 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
5907 << GLES2Util::GetStringEnum(target) << ")");
5908 switch (target) {
5909 case GL_ARRAY_BUFFER:
5910 case GL_ATOMIC_COUNTER_BUFFER:
5911 case GL_ELEMENT_ARRAY_BUFFER:
5912 case GL_COPY_READ_BUFFER:
5913 case GL_COPY_WRITE_BUFFER:
5914 case GL_DISPATCH_INDIRECT_BUFFER:
5915 case GL_DRAW_INDIRECT_BUFFER:
5916 case GL_PIXEL_PACK_BUFFER:
5917 case GL_PIXEL_UNPACK_BUFFER:
5918 case GL_SHADER_STORAGE_BUFFER:
5919 case GL_TRANSFORM_FEEDBACK_BUFFER:
5920 case GL_UNIFORM_BUFFER:
5921 break;
5922 default:
5923 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
5924 return GL_FALSE;
5925 }
5926 GLuint buffer = GetBoundBufferHelper(target);
5927 if (buffer == 0) {
5928 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
5929 return GL_FALSE;
5930 }
5931 auto iter = mapped_buffer_range_map_.find(buffer);
5932 if (iter == mapped_buffer_range_map_.end()) {
5933 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
5934 return GL_FALSE;
5935 }
5936
5937 bool was_mapped_by_readback_tracker = false;
5938 if (auto* buffer_object =
5939 readback_buffer_shadow_tracker_->GetBuffer(buffer)) {
5940 was_mapped_by_readback_tracker = buffer_object->UnmapReadbackShm();
5941 }
5942 if (!was_mapped_by_readback_tracker) {
5943 helper_->UnmapBuffer(target);
5944 InvalidateReadbackBufferShadowDataCHROMIUM(GetBoundBufferHelper(target));
5945 }
5946 RemoveMappedBufferRangeById(buffer);
5947
5948 // TODO(zmo): There is a rare situation that data might be corrupted and
5949 // GL_FALSE should be returned. We lose context on that sitatuon, so we
5950 // don't have to WaitForCmd().
5951 GPU_CLIENT_LOG(" returned " << GL_TRUE);
5952 CheckGLError();
5953 return GL_TRUE;
5954 }
5955
MapTexSubImage2DCHROMIUM(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,GLenum access)5956 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(GLenum target,
5957 GLint level,
5958 GLint xoffset,
5959 GLint yoffset,
5960 GLsizei width,
5961 GLsizei height,
5962 GLenum format,
5963 GLenum type,
5964 GLenum access) {
5965 GPU_CLIENT_SINGLE_THREAD_CHECK();
5966 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
5967 << target << ", " << level << ", " << xoffset << ", "
5968 << yoffset << ", " << width << ", " << height << ", "
5969 << GLES2Util::GetStringTextureFormat(format) << ", "
5970 << GLES2Util::GetStringPixelType(type) << ", "
5971 << GLES2Util::GetStringEnum(access) << ")");
5972 if (access != GL_WRITE_ONLY) {
5973 SetGLErrorInvalidEnum("glMapTexSubImage2DCHROMIUM", access, "access");
5974 return nullptr;
5975 }
5976 // NOTE: target is NOT checked because the service will check it
5977 // and we don't know what targets are valid.
5978 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
5979 SetGLError(GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM",
5980 "bad dimensions");
5981 return nullptr;
5982 }
5983 uint32_t size;
5984 if (!GLES2Util::ComputeImageDataSizes(width, height, 1, format, type,
5985 unpack_alignment_, &size, nullptr,
5986 nullptr)) {
5987 SetGLError(GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM",
5988 "image size too large");
5989 return nullptr;
5990 }
5991 int32_t shm_id;
5992 unsigned int shm_offset;
5993 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
5994 if (!mem) {
5995 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
5996 return nullptr;
5997 }
5998
5999 std::pair<MappedTextureMap::iterator, bool> result =
6000 mapped_textures_.insert(std::make_pair(
6001 mem, MappedTexture(access, shm_id, mem, shm_offset, target, level,
6002 xoffset, yoffset, width, height, format, type)));
6003 DCHECK(result.second);
6004 GPU_CLIENT_LOG(" returned " << mem);
6005 return mem;
6006 }
6007
UnmapTexSubImage2DCHROMIUM(const void * mem)6008 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
6009 GPU_CLIENT_SINGLE_THREAD_CHECK();
6010 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM("
6011 << mem << ")");
6012 MappedTextureMap::iterator it = mapped_textures_.find(mem);
6013 if (it == mapped_textures_.end()) {
6014 SetGLError(GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM",
6015 "texture not mapped");
6016 return;
6017 }
6018 const MappedTexture& mt = it->second;
6019 helper_->TexSubImage2D(mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width,
6020 mt.height, mt.format, mt.type, mt.shm_id,
6021 mt.shm_offset, GL_FALSE);
6022 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
6023 mapped_textures_.erase(it);
6024 CheckGLError();
6025 }
6026
ResizeCHROMIUM(GLuint width,GLuint height,float scale_factor,GLcolorSpace gl_color_space,GLboolean alpha)6027 void GLES2Implementation::ResizeCHROMIUM(GLuint width,
6028 GLuint height,
6029 float scale_factor,
6030 GLcolorSpace gl_color_space,
6031 GLboolean alpha) {
6032 GPU_CLIENT_SINGLE_THREAD_CHECK();
6033 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM(" << width << ", "
6034 << height << ", " << scale_factor << ", " << alpha << ")");
6035 // Including gfx::ColorSpace would bring Skia and a lot of other code into
6036 // NaCl's IRT, so just leave the color space unspecified.
6037 #if !defined(__native_client__)
6038 if (gl_color_space) {
6039 gfx::ColorSpace gfx_color_space =
6040 *reinterpret_cast<const gfx::ColorSpace*>(gl_color_space);
6041 base::Pickle color_space_data;
6042 IPC::ParamTraits<gfx::ColorSpace>::Write(&color_space_data,
6043 gfx_color_space);
6044 ScopedTransferBufferPtr buffer(color_space_data.size(), helper_,
6045 transfer_buffer_);
6046 if (!buffer.valid() || buffer.size() < color_space_data.size()) {
6047 SetGLError(GL_OUT_OF_MEMORY, "GLES2::SetColorSpaceMetadataCHROMIUM",
6048 "out of memory");
6049 return;
6050 }
6051 memcpy(buffer.address(), color_space_data.data(), color_space_data.size());
6052 helper_->ResizeCHROMIUM(width, height, scale_factor, alpha, buffer.shm_id(),
6053 buffer.offset(), color_space_data.size());
6054 CheckGLError();
6055 return;
6056 }
6057 #endif
6058 helper_->ResizeCHROMIUM(width, height, scale_factor, alpha, 0, 0, 0);
6059 CheckGLError();
6060 }
6061
GetRequestableExtensionsCHROMIUM()6062 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
6063 GPU_CLIENT_SINGLE_THREAD_CHECK();
6064 GPU_CLIENT_LOG("[" << GetLogPrefix()
6065 << "] glGetRequestableExtensionsCHROMIUM()");
6066 TRACE_EVENT0("gpu",
6067 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
6068 const char* result = nullptr;
6069 // Clear the bucket so if the command fails nothing will be in it.
6070 helper_->SetBucketSize(kResultBucketId, 0);
6071 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
6072 std::string str;
6073 if (GetBucketAsString(kResultBucketId, &str)) {
6074 // The set of requestable extensions shrinks as we enable
6075 // them. Because we don't know when the client will stop referring
6076 // to a previous one it queries (see GetString) we need to cache
6077 // the unique results.
6078 // TODO: Here we could save memory by defining RequestExtensions
6079 // invalidating the GL_EXTENSIONS string. http://crbug.com/586414
6080 result = gl_strings_.insert(str).first->c_str();
6081 }
6082 GPU_CLIENT_LOG(" returned " << result);
6083 return reinterpret_cast<const GLchar*>(result);
6084 }
6085
6086 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
6087 // with VirtualGL contexts.
RequestExtensionCHROMIUM(const char * extension)6088 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
6089 GPU_CLIENT_SINGLE_THREAD_CHECK();
6090 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
6091 << extension << ")");
6092 InvalidateCachedExtensions();
6093 SetBucketAsCString(kResultBucketId, extension);
6094 helper_->RequestExtensionCHROMIUM(kResultBucketId);
6095 helper_->SetBucketSize(kResultBucketId, 0);
6096
6097 struct ExtensionCheck {
6098 const char* extension;
6099 ExtensionStatus* status;
6100 };
6101 const ExtensionCheck checks[] = {
6102 {
6103 "GL_CHROMIUM_framebuffer_multisample",
6104 &chromium_framebuffer_multisample_,
6105 },
6106 };
6107 const size_t kNumChecks = sizeof(checks) / sizeof(checks[0]);
6108 for (size_t ii = 0; ii < kNumChecks; ++ii) {
6109 const ExtensionCheck& check = checks[ii];
6110 if (*check.status == kUnavailableExtensionStatus &&
6111 !strcmp(extension, check.extension)) {
6112 *check.status = kUnknownExtensionStatus;
6113 }
6114 }
6115 }
6116
GetProgramInfoCHROMIUMHelper(GLuint program,std::vector<int8_t> * result)6117 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
6118 GLuint program,
6119 std::vector<int8_t>* result) {
6120 DCHECK(result);
6121 // Clear the bucket so if the command fails nothing will be in it.
6122 helper_->SetBucketSize(kResultBucketId, 0);
6123 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
6124 GetBucketContents(kResultBucketId, result);
6125 }
6126
GetProgramInfoCHROMIUM(GLuint program,GLsizei bufsize,GLsizei * size,void * info)6127 void GLES2Implementation::GetProgramInfoCHROMIUM(GLuint program,
6128 GLsizei bufsize,
6129 GLsizei* size,
6130 void* info) {
6131 GPU_CLIENT_SINGLE_THREAD_CHECK();
6132 if (bufsize < 0) {
6133 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM",
6134 "bufsize less than 0.");
6135 return;
6136 }
6137 if (size == nullptr) {
6138 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
6139 return;
6140 }
6141 // Make sure they've set size to 0 else the value will be undefined on
6142 // lost context.
6143 DCHECK_EQ(0, *size);
6144 std::vector<int8_t> result;
6145 GetProgramInfoCHROMIUMHelper(program, &result);
6146 if (result.empty()) {
6147 return;
6148 }
6149 *size = result.size();
6150 if (!info) {
6151 return;
6152 }
6153 if (static_cast<size_t>(bufsize) < result.size()) {
6154 SetGLError(GL_INVALID_OPERATION, "glProgramInfoCHROMIUM",
6155 "bufsize is too small for result.");
6156 return;
6157 }
6158 memcpy(info, &result[0], result.size());
6159 }
6160
GetUniformBlocksCHROMIUMHelper(GLuint program,std::vector<int8_t> * result)6161 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
6162 GLuint program,
6163 std::vector<int8_t>* result) {
6164 DCHECK(result);
6165 // Clear the bucket so if the command fails nothing will be in it.
6166 helper_->SetBucketSize(kResultBucketId, 0);
6167 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
6168 GetBucketContents(kResultBucketId, result);
6169 }
6170
GetUniformBlocksCHROMIUM(GLuint program,GLsizei bufsize,GLsizei * size,void * info)6171 void GLES2Implementation::GetUniformBlocksCHROMIUM(GLuint program,
6172 GLsizei bufsize,
6173 GLsizei* size,
6174 void* info) {
6175 GPU_CLIENT_SINGLE_THREAD_CHECK();
6176 if (bufsize < 0) {
6177 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM",
6178 "bufsize less than 0.");
6179 return;
6180 }
6181 if (size == nullptr) {
6182 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
6183 return;
6184 }
6185 // Make sure they've set size to 0 else the value will be undefined on
6186 // lost context.
6187 DCHECK_EQ(0, *size);
6188 std::vector<int8_t> result;
6189 GetUniformBlocksCHROMIUMHelper(program, &result);
6190 if (result.empty()) {
6191 return;
6192 }
6193 *size = result.size();
6194 if (!info) {
6195 return;
6196 }
6197 if (static_cast<size_t>(bufsize) < result.size()) {
6198 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
6199 "bufsize is too small for result.");
6200 return;
6201 }
6202 memcpy(info, &result[0], result.size());
6203 }
6204
GetUniformsES3CHROMIUMHelper(GLuint program,std::vector<int8_t> * result)6205 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
6206 GLuint program,
6207 std::vector<int8_t>* result) {
6208 DCHECK(result);
6209 // Clear the bucket so if the command fails nothing will be in it.
6210 helper_->SetBucketSize(kResultBucketId, 0);
6211 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
6212 GetBucketContents(kResultBucketId, result);
6213 }
6214
GetUniformsES3CHROMIUM(GLuint program,GLsizei bufsize,GLsizei * size,void * info)6215 void GLES2Implementation::GetUniformsES3CHROMIUM(GLuint program,
6216 GLsizei bufsize,
6217 GLsizei* size,
6218 void* info) {
6219 GPU_CLIENT_SINGLE_THREAD_CHECK();
6220 if (bufsize < 0) {
6221 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM",
6222 "bufsize less than 0.");
6223 return;
6224 }
6225 if (size == nullptr) {
6226 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
6227 return;
6228 }
6229 // Make sure they've set size to 0 else the value will be undefined on
6230 // lost context.
6231 DCHECK_EQ(0, *size);
6232 std::vector<int8_t> result;
6233 GetUniformsES3CHROMIUMHelper(program, &result);
6234 if (result.empty()) {
6235 return;
6236 }
6237 *size = result.size();
6238 if (!info) {
6239 return;
6240 }
6241 if (static_cast<size_t>(bufsize) < result.size()) {
6242 SetGLError(GL_INVALID_OPERATION, "glGetUniformsES3CHROMIUM",
6243 "bufsize is too small for result.");
6244 return;
6245 }
6246 memcpy(info, &result[0], result.size());
6247 }
6248
GetTransformFeedbackVaryingsCHROMIUMHelper(GLuint program,std::vector<int8_t> * result)6249 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
6250 GLuint program,
6251 std::vector<int8_t>* result) {
6252 DCHECK(result);
6253 // Clear the bucket so if the command fails nothing will be in it.
6254 helper_->SetBucketSize(kResultBucketId, 0);
6255 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
6256 GetBucketContents(kResultBucketId, result);
6257 }
6258
GetTransformFeedbackVaryingsCHROMIUM(GLuint program,GLsizei bufsize,GLsizei * size,void * info)6259 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
6260 GLsizei bufsize,
6261 GLsizei* size,
6262 void* info) {
6263 GPU_CLIENT_SINGLE_THREAD_CHECK();
6264 if (bufsize < 0) {
6265 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
6266 "bufsize less than 0.");
6267 return;
6268 }
6269 if (size == nullptr) {
6270 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
6271 "size is null.");
6272 return;
6273 }
6274 // Make sure they've set size to 0 else the value will be undefined on
6275 // lost context.
6276 DCHECK_EQ(0, *size);
6277 std::vector<int8_t> result;
6278 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
6279 if (result.empty()) {
6280 return;
6281 }
6282 *size = result.size();
6283 if (!info) {
6284 return;
6285 }
6286 if (static_cast<size_t>(bufsize) < result.size()) {
6287 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
6288 "bufsize is too small for result.");
6289 return;
6290 }
6291 memcpy(info, &result[0], result.size());
6292 }
6293
PostSubBufferCHROMIUM(uint64_t swap_id,GLint x,GLint y,GLint width,GLint height,GLbitfield flags)6294 void GLES2Implementation::PostSubBufferCHROMIUM(uint64_t swap_id,
6295 GLint x,
6296 GLint y,
6297 GLint width,
6298 GLint height,
6299 GLbitfield flags) {
6300 GPU_CLIENT_SINGLE_THREAD_CHECK();
6301 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM(" << x
6302 << ", " << y << ", " << width << ", " << height << ")");
6303 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM", "width", width, "height",
6304 height);
6305
6306 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
6307 swap_buffers_tokens_.push(helper_->InsertToken());
6308 helper_->PostSubBufferCHROMIUM(swap_id, x, y, width, height, flags);
6309 helper_->CommandBufferHelper::Flush();
6310 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
6311 helper_->WaitForToken(swap_buffers_tokens_.front());
6312 swap_buffers_tokens_.pop();
6313 }
6314 }
6315
DeleteQueriesEXTHelper(GLsizei n,const GLuint * queries)6316 void GLES2Implementation::DeleteQueriesEXTHelper(GLsizei n,
6317 const GLuint* queries) {
6318 IdAllocator* id_allocator = GetIdAllocator(IdNamespaces::kQueries);
6319 for (GLsizei ii = 0; ii < n; ++ii) {
6320 query_tracker_->RemoveQuery(queries[ii]);
6321 id_allocator->FreeID(queries[ii]);
6322 }
6323
6324 helper_->DeleteQueriesEXTImmediate(n, queries);
6325 }
6326
IsQueryEXT(GLuint id)6327 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
6328 GPU_CLIENT_SINGLE_THREAD_CHECK();
6329 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
6330
6331 // TODO(gman): To be spec compliant IDs from other contexts sharing
6332 // resources need to return true here even though you can't share
6333 // queries across contexts?
6334 return query_tracker_->GetQuery(id) != nullptr;
6335 }
6336
BeginQueryEXT(GLenum target,GLuint id)6337 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
6338 GPU_CLIENT_SINGLE_THREAD_CHECK();
6339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
6340 << GLES2Util::GetStringQueryTarget(target) << ", " << id
6341 << ")");
6342
6343 switch (target) {
6344 case GL_COMMANDS_ISSUED_CHROMIUM:
6345 case GL_LATENCY_QUERY_CHROMIUM:
6346 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
6347 case GL_GET_ERROR_QUERY_CHROMIUM:
6348 case GL_PROGRAM_COMPLETION_QUERY_CHROMIUM:
6349 break;
6350 case GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM:
6351 case GL_COMMANDS_COMPLETED_CHROMIUM:
6352 if (!capabilities_.sync_query) {
6353 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT",
6354 "not enabled for commands completed queries");
6355 return;
6356 }
6357 break;
6358 case GL_SAMPLES_PASSED_ARB:
6359 if (!capabilities_.occlusion_query) {
6360 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT",
6361 "not enabled for occlusion queries");
6362 return;
6363 }
6364 break;
6365 case GL_ANY_SAMPLES_PASSED:
6366 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
6367 if (!capabilities_.occlusion_query_boolean) {
6368 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT",
6369 "not enabled for boolean occlusion queries");
6370 return;
6371 }
6372 break;
6373 case GL_TIME_ELAPSED_EXT:
6374 if (!capabilities_.timer_queries) {
6375 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT",
6376 "not enabled for timing queries");
6377 return;
6378 }
6379 break;
6380 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
6381 if (capabilities_.major_version >= 3)
6382 break;
6383 FALLTHROUGH;
6384 default:
6385 SetGLError(GL_INVALID_ENUM, "glBeginQueryEXT", "unknown query target");
6386 return;
6387 }
6388
6389 // if any outstanding queries INV_OP
6390 if (query_tracker_->GetCurrentQuery(target)) {
6391 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT",
6392 "query already in progress");
6393 return;
6394 }
6395
6396 if (id == 0) {
6397 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
6398 return;
6399 }
6400
6401 if (!GetIdAllocator(IdNamespaces::kQueries)->InUse(id)) {
6402 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
6403 return;
6404 }
6405
6406 // Extra setups some targets might need.
6407 switch (target) {
6408 case GL_TIME_ELAPSED_EXT:
6409 if (!query_tracker_->SetDisjointSync(this)) {
6410 SetGLError(GL_OUT_OF_MEMORY, "glBeginQueryEXT",
6411 "buffer allocation failed");
6412 return;
6413 }
6414 break;
6415 default:
6416 break;
6417 }
6418
6419 if (query_tracker_->BeginQuery(id, target, this))
6420 CheckGLError();
6421
6422 if (target == GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM) {
6423 AllocateShadowCopiesForReadback();
6424 }
6425 }
6426
AllocateShadowCopiesForReadback()6427 void GLES2Implementation::AllocateShadowCopiesForReadback() {
6428 for (auto buffer : readback_buffer_shadow_tracker_->GetUnfencedBufferList()) {
6429 if (!buffer) {
6430 continue;
6431 }
6432 int32_t shm_id = 0;
6433 uint32_t shm_offset = 0;
6434 bool already_allocated = false;
6435 uint32_t size = buffer->Alloc(&shm_id, &shm_offset, &already_allocated);
6436 if (already_allocated) {
6437 SendErrorMessage(
6438 "performance warning: READ-usage buffer was written, then "
6439 "fenced, but written again before being read back. This discarded "
6440 "the shadow copy that was created to accelerate readback.",
6441 0);
6442 }
6443 helper_->SetReadbackBufferShadowAllocationINTERNAL(buffer->id(), shm_id,
6444 shm_offset, size);
6445 }
6446 }
6447
BufferShadowWrittenCallback(const ReadbackBufferShadowTracker::BufferList & buffers,uint64_t serial)6448 void GLES2Implementation::BufferShadowWrittenCallback(
6449 const ReadbackBufferShadowTracker::BufferList& buffers,
6450 uint64_t serial) {
6451 for (const auto& buffer : buffers) {
6452 if (buffer) {
6453 buffer->UpdateSerialTo(serial);
6454 }
6455 }
6456 }
6457
EndQueryEXT(GLenum target)6458 void GLES2Implementation::EndQueryEXT(GLenum target) {
6459 QueryTracker::Query* query = nullptr;
6460 {
6461 GPU_CLIENT_SINGLE_THREAD_CHECK();
6462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
6463 << GLES2Util::GetStringQueryTarget(target) << ")");
6464 query = query_tracker_->GetCurrentQuery(target);
6465 if (!query_tracker_->EndQuery(target, this)) {
6466 return;
6467 }
6468 CheckGLError();
6469 } // GPU_CLIENT_SINGLE_THREAD_CHECK ends here
6470
6471 if (target == GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM) {
6472 DCHECK(capabilities_.chromium_nonblocking_readback);
6473 DCHECK(query);
6474 auto serial = readback_buffer_shadow_tracker_->buffer_shadow_serial();
6475 readback_buffer_shadow_tracker_->IncrementSerial();
6476 auto buffers = readback_buffer_shadow_tracker_->TakeUnfencedBufferList();
6477 query->SetCompletedCallback(
6478 base::BindOnce(&GLES2Implementation::BufferShadowWrittenCallback,
6479 std::move(buffers), serial));
6480 }
6481 }
6482
QueryCounterEXT(GLuint id,GLenum target)6483 void GLES2Implementation::QueryCounterEXT(GLuint id, GLenum target) {
6484 GPU_CLIENT_SINGLE_THREAD_CHECK();
6485 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] QueryCounterEXT(" << id << ", "
6486 << GLES2Util::GetStringQueryTarget(target) << ")");
6487
6488 switch (target) {
6489 case GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM:
6490 break;
6491 case GL_TIMESTAMP_EXT:
6492 if (!capabilities_.timer_queries) {
6493 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT",
6494 "not enabled for timing queries");
6495 return;
6496 }
6497 break;
6498 default:
6499 SetGLError(GL_INVALID_ENUM, "glQueryCounterEXT", "unknown query target");
6500 return;
6501 }
6502
6503 if (id == 0) {
6504 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "id is 0");
6505 return;
6506 }
6507
6508 if (!GetIdAllocator(IdNamespaces::kQueries)->InUse(id)) {
6509 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "invalid id");
6510 return;
6511 }
6512
6513 // Extra setups some targets might need.
6514 switch (target) {
6515 case GL_TIMESTAMP_EXT:
6516 if (!query_tracker_->SetDisjointSync(this)) {
6517 SetGLError(GL_OUT_OF_MEMORY, "glQueryCounterEXT",
6518 "buffer allocation failed");
6519 return;
6520 }
6521 break;
6522 default:
6523 break;
6524 }
6525
6526 if (query_tracker_->QueryCounter(id, target, this))
6527 CheckGLError();
6528 }
6529
GetQueryivEXT(GLenum target,GLenum pname,GLint * params)6530 void GLES2Implementation::GetQueryivEXT(GLenum target,
6531 GLenum pname,
6532 GLint* params) {
6533 GPU_CLIENT_SINGLE_THREAD_CHECK();
6534 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
6535 << GLES2Util::GetStringQueryTarget(target) << ", "
6536 << GLES2Util::GetStringQueryParameter(pname) << ", "
6537 << static_cast<const void*>(params) << ")");
6538 if (pname == GL_QUERY_COUNTER_BITS_EXT) {
6539 switch (target) {
6540 case GL_TIMESTAMP_EXT:
6541 // Overall reliable driver support for timestamps is limited, so we
6542 // disable the timestamp portion of this extension to encourage use of
6543 // the better supported time elapsed queries.
6544 *params = 0;
6545 break;
6546 case GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM:
6547 case GL_TIME_ELAPSED_EXT:
6548 // We convert all queries to CPU time so we support 64 bits.
6549 *params = 64;
6550 break;
6551 default:
6552 SetGLErrorInvalidEnum("glGetQueryivEXT", target, "target");
6553 break;
6554 }
6555 return;
6556 } else if (pname != GL_CURRENT_QUERY_EXT) {
6557 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
6558 return;
6559 }
6560 QueryTracker::Query* query = query_tracker_->GetCurrentQuery(target);
6561 *params = query ? query->id() : 0;
6562 GPU_CLIENT_LOG(" " << *params);
6563 CheckGLError();
6564 }
6565
GetQueryObjectivEXT(GLuint id,GLenum pname,GLint * params)6566 void GLES2Implementation::GetQueryObjectivEXT(GLuint id,
6567 GLenum pname,
6568 GLint* params) {
6569 GLuint64 result = 0;
6570 if (GetQueryObjectValueHelper("glGetQueryObjectivEXT", id, pname, &result))
6571 *params = base::saturated_cast<GLint>(result);
6572 }
6573
GetQueryObjectuivEXT(GLuint id,GLenum pname,GLuint * params)6574 void GLES2Implementation::GetQueryObjectuivEXT(GLuint id,
6575 GLenum pname,
6576 GLuint* params) {
6577 GLuint64 result = 0;
6578 if (GetQueryObjectValueHelper("glGetQueryObjectuivEXT", id, pname, &result))
6579 *params = base::saturated_cast<GLuint>(result);
6580 }
6581
GetQueryObjecti64vEXT(GLuint id,GLenum pname,GLint64 * params)6582 void GLES2Implementation::GetQueryObjecti64vEXT(GLuint id,
6583 GLenum pname,
6584 GLint64* params) {
6585 GLuint64 result = 0;
6586 if (GetQueryObjectValueHelper("glGetQueryObjectiv64vEXT", id, pname, &result))
6587 *params = base::saturated_cast<GLint64>(result);
6588 }
6589
GetQueryObjectui64vEXT(GLuint id,GLenum pname,GLuint64 * params)6590 void GLES2Implementation::GetQueryObjectui64vEXT(GLuint id,
6591 GLenum pname,
6592 GLuint64* params) {
6593 GLuint64 result = 0;
6594 if (GetQueryObjectValueHelper("glGetQueryObjectui64vEXT", id, pname, &result))
6595 *params = result;
6596 }
6597
SetDisjointValueSyncCHROMIUM()6598 void GLES2Implementation::SetDisjointValueSyncCHROMIUM() {
6599 query_tracker_->SetDisjointSync(this);
6600 }
6601
DrawArraysInstancedANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount)6602 void GLES2Implementation::DrawArraysInstancedANGLE(GLenum mode,
6603 GLint first,
6604 GLsizei count,
6605 GLsizei primcount) {
6606 GPU_CLIENT_SINGLE_THREAD_CHECK();
6607 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
6608 << GLES2Util::GetStringDrawMode(mode) << ", " << first
6609 << ", " << count << ", " << primcount << ")");
6610 if (count < 0) {
6611 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
6612 return;
6613 }
6614 if (primcount < 0) {
6615 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
6616 return;
6617 }
6618 if (primcount == 0) {
6619 return;
6620 }
6621 bool simulated = false;
6622 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
6623 GLsizei num_elements;
6624 if (!base::CheckAdd(first, count).AssignIfValid(&num_elements)) {
6625 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE",
6626 "first+count overflow");
6627 return;
6628 }
6629 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
6630 "glDrawArraysInstancedANGLE", this, helper_, num_elements,
6631 primcount, &simulated)) {
6632 return;
6633 }
6634 }
6635 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
6636 RestoreArrayBuffer(simulated);
6637 CheckGLError();
6638 }
6639
DrawArraysInstancedBaseInstanceANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount,GLuint baseinstance)6640 void GLES2Implementation::DrawArraysInstancedBaseInstanceANGLE(
6641 GLenum mode,
6642 GLint first,
6643 GLsizei count,
6644 GLsizei primcount,
6645 GLuint baseinstance) {
6646 GPU_CLIENT_SINGLE_THREAD_CHECK();
6647 GPU_CLIENT_LOG(
6648 "[" << GetLogPrefix() << "] glDrawArraysInstancedBaseInstanceANGLE("
6649 << GLES2Util::GetStringDrawMode(mode) << ", " << first << ", "
6650 << count << ", " << primcount << ", " << baseinstance << ")");
6651 if (count < 0) {
6652 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedBaseInstanceANGLE",
6653 "count < 0");
6654 return;
6655 }
6656 if (primcount < 0) {
6657 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedBaseInstanceANGLE",
6658 "primcount < 0");
6659 return;
6660 }
6661 if (primcount == 0) {
6662 return;
6663 }
6664 bool simulated = false;
6665 if (vertex_array_object_manager_->SupportsClientSideBuffers()) {
6666 GLsizei num_elements;
6667 if (!base::CheckAdd(first, count).AssignIfValid(&num_elements)) {
6668 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedBaseInstanceANGLE",
6669 "first+count overflow");
6670 return;
6671 }
6672 // Client side buffer is not used by WebGL so leave it as is.
6673 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
6674 "glDrawArraysInstancedBaseInstanceANGLE", this, helper_,
6675 num_elements, primcount, &simulated)) {
6676 return;
6677 }
6678 }
6679 helper_->DrawArraysInstancedBaseInstanceANGLE(mode, first, count, primcount,
6680 baseinstance);
6681 RestoreArrayBuffer(simulated);
6682 CheckGLError();
6683 }
6684
DrawElementsInstancedANGLE(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei primcount)6685 void GLES2Implementation::DrawElementsInstancedANGLE(GLenum mode,
6686 GLsizei count,
6687 GLenum type,
6688 const void* indices,
6689 GLsizei primcount) {
6690 GPU_CLIENT_SINGLE_THREAD_CHECK();
6691 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
6692 << GLES2Util::GetStringDrawMode(mode) << ", " << count
6693 << ", " << GLES2Util::GetStringIndexType(type) << ", "
6694 << static_cast<const void*>(indices) << ", " << primcount
6695 << ")");
6696 if (count < 0) {
6697 SetGLError(GL_INVALID_VALUE, "glDrawElementsInstancedANGLE",
6698 "count less than 0.");
6699 return;
6700 }
6701 if (primcount < 0) {
6702 SetGLError(GL_INVALID_VALUE, "glDrawElementsInstancedANGLE",
6703 "primcount < 0");
6704 return;
6705 }
6706 GLuint offset = 0;
6707 bool simulated = false;
6708 if (count > 0 && primcount > 0) {
6709 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
6710 !ValidateOffset("glDrawElementsInstancedANGLE",
6711 reinterpret_cast<GLintptr>(indices))) {
6712 return;
6713 }
6714 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
6715 "glDrawElementsInstancedANGLE", this, helper_, count, type,
6716 primcount, indices, &offset, &simulated)) {
6717 return;
6718 }
6719 }
6720 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
6721 RestoreElementAndArrayBuffers(simulated);
6722 CheckGLError();
6723 }
6724
DrawElementsInstancedBaseVertexBaseInstanceANGLE(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei primcount,GLint basevertex,GLuint baseinstance)6725 void GLES2Implementation::DrawElementsInstancedBaseVertexBaseInstanceANGLE(
6726 GLenum mode,
6727 GLsizei count,
6728 GLenum type,
6729 const void* indices,
6730 GLsizei primcount,
6731 GLint basevertex,
6732 GLuint baseinstance) {
6733 GPU_CLIENT_SINGLE_THREAD_CHECK();
6734 GPU_CLIENT_LOG("[" << GetLogPrefix()
6735 << "] glDrawElementsInstancedBaseVertexBaseInstanceANGLE("
6736 << GLES2Util::GetStringDrawMode(mode) << ", " << count
6737 << ", " << GLES2Util::GetStringIndexType(type) << ", "
6738 << static_cast<const void*>(indices) << ", " << primcount
6739 << ", " << basevertex << ", " << baseinstance << ")");
6740 if (count < 0) {
6741 SetGLError(GL_INVALID_VALUE,
6742 "glDrawElementsInstancedBaseVertexBaseInstanceANGLE",
6743 "count less than 0.");
6744 return;
6745 }
6746 if (primcount < 0) {
6747 SetGLError(GL_INVALID_VALUE,
6748 "glDrawElementsInstancedBaseVertexBaseInstanceANGLE",
6749 "primcount < 0");
6750 return;
6751 }
6752 GLuint offset = 0;
6753 bool simulated = false;
6754 if (count > 0 && primcount > 0) {
6755 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
6756 !ValidateOffset("glDrawElementsInstancedBaseVertexBaseInstanceANGLE",
6757 reinterpret_cast<GLintptr>(indices))) {
6758 return;
6759 }
6760 // Client side buffer is not used by WebGL so leave it as is.
6761 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
6762 "glDrawElementsInstancedBaseVertexBaseInstanceANGLE", this, helper_,
6763 count, type, primcount, indices, &offset, &simulated)) {
6764 return;
6765 }
6766 }
6767 helper_->DrawElementsInstancedBaseVertexBaseInstanceANGLE(
6768 mode, count, type, offset, primcount, basevertex, baseinstance);
6769 RestoreElementAndArrayBuffers(simulated);
6770 CheckGLError();
6771 }
6772
ProduceTextureDirectCHROMIUM(GLuint texture,GLbyte * data)6773 void GLES2Implementation::ProduceTextureDirectCHROMIUM(GLuint texture,
6774 GLbyte* data) {
6775 GPU_CLIENT_SINGLE_THREAD_CHECK();
6776 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
6777 << static_cast<const void*>(data) << ")");
6778 static_assert(std::is_trivially_copyable<Mailbox>::value,
6779 "gpu::Mailbox is not trivially copyable");
6780 Mailbox result = Mailbox::Generate();
6781 memcpy(data, result.name, sizeof(result.name));
6782 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, data);
6783 CheckGLError();
6784 }
6785
CreateAndConsumeTextureCHROMIUM(const GLbyte * data)6786 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
6787 const GLbyte* data) {
6788 GPU_CLIENT_SINGLE_THREAD_CHECK();
6789 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
6790 << static_cast<const void*>(data) << ")");
6791 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
6792 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
6793 "mailbox that was not generated by "
6794 "ProduceTextureDirectCHROMIUM.";
6795 GLuint client_id;
6796 GetIdHandler(SharedIdNamespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
6797 helper_->CreateAndConsumeTextureINTERNALImmediate(client_id, data);
6798 if (share_group_->bind_generates_resource())
6799 helper_->CommandBufferHelper::OrderingBarrier();
6800 CheckGLError();
6801 return client_id;
6802 }
6803
CreateAndTexStorage2DSharedImageCHROMIUM(const GLbyte * mailbox_data)6804 GLuint GLES2Implementation::CreateAndTexStorage2DSharedImageCHROMIUM(
6805 const GLbyte* mailbox_data) {
6806 GPU_CLIENT_SINGLE_THREAD_CHECK();
6807 GPU_CLIENT_LOG("[" << GetLogPrefix()
6808 << "] CreateAndTexStorage2DSharedImageCHROMIUM("
6809 << static_cast<const void*>(mailbox_data) << ")");
6810 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(mailbox_data);
6811 DCHECK(mailbox.Verify()) << "CreateAndTexStorage2DSharedImageCHROMIUM was "
6812 "passed an invalid mailbox.";
6813 DCHECK(mailbox.IsSharedImage());
6814 GLuint client_id;
6815 GetIdHandler(SharedIdNamespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
6816 helper_->CreateAndTexStorage2DSharedImageINTERNALImmediate(client_id, GL_NONE,
6817 mailbox_data);
6818 if (share_group_->bind_generates_resource())
6819 helper_->CommandBufferHelper::OrderingBarrier();
6820 CheckGLError();
6821 return client_id;
6822 }
6823
6824 GLuint
CreateAndTexStorage2DSharedImageWithInternalFormatCHROMIUM(const GLbyte * mailbox_data,GLenum internalformat)6825 GLES2Implementation::CreateAndTexStorage2DSharedImageWithInternalFormatCHROMIUM(
6826 const GLbyte* mailbox_data,
6827 GLenum internalformat) {
6828 GPU_CLIENT_SINGLE_THREAD_CHECK();
6829 GPU_CLIENT_LOG(
6830 "[" << GetLogPrefix()
6831 << "] CreateAndTexStorage2DSharedImageWithInternalFormatCHROMIUM("
6832 << static_cast<const void*>(mailbox_data) << ", " << internalformat
6833 << ")");
6834 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(mailbox_data);
6835 DCHECK(mailbox.Verify())
6836 << "CreateAndTexStorage2DSharedImageWithInternalFormatCHROMIUM was "
6837 "passed an invalid mailbox.";
6838 DCHECK(mailbox.IsSharedImage());
6839 GLuint client_id;
6840 GetIdHandler(SharedIdNamespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
6841 helper_->CreateAndTexStorage2DSharedImageINTERNALImmediate(
6842 client_id, internalformat, mailbox_data);
6843 if (share_group_->bind_generates_resource())
6844 helper_->CommandBufferHelper::OrderingBarrier();
6845 CheckGLError();
6846 return client_id;
6847 }
6848
PushGroupMarkerEXT(GLsizei length,const GLchar * marker)6849 void GLES2Implementation::PushGroupMarkerEXT(GLsizei length,
6850 const GLchar* marker) {
6851 GPU_CLIENT_SINGLE_THREAD_CHECK();
6852 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT(" << length
6853 << ", " << marker << ")");
6854 if (!marker) {
6855 marker = "";
6856 }
6857 SetBucketAsString(kResultBucketId, (length ? std::string(marker, length)
6858 : std::string(marker)));
6859 helper_->PushGroupMarkerEXT(kResultBucketId);
6860 helper_->SetBucketSize(kResultBucketId, 0);
6861 debug_marker_manager_.PushGroup(length ? std::string(marker, length)
6862 : std::string(marker));
6863 }
6864
InsertEventMarkerEXT(GLsizei length,const GLchar * marker)6865 void GLES2Implementation::InsertEventMarkerEXT(GLsizei length,
6866 const GLchar* marker) {
6867 GPU_CLIENT_SINGLE_THREAD_CHECK();
6868 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT(" << length
6869 << ", " << marker << ")");
6870 if (!marker) {
6871 marker = "";
6872 }
6873 SetBucketAsString(kResultBucketId, (length ? std::string(marker, length)
6874 : std::string(marker)));
6875 helper_->InsertEventMarkerEXT(kResultBucketId);
6876 helper_->SetBucketSize(kResultBucketId, 0);
6877 debug_marker_manager_.SetMarker(length ? std::string(marker, length)
6878 : std::string(marker));
6879 }
6880
PopGroupMarkerEXT()6881 void GLES2Implementation::PopGroupMarkerEXT() {
6882 GPU_CLIENT_SINGLE_THREAD_CHECK();
6883 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
6884 helper_->PopGroupMarkerEXT();
6885 debug_marker_manager_.PopGroup();
6886 }
6887
TraceBeginCHROMIUM(const char * category_name,const char * trace_name)6888 void GLES2Implementation::TraceBeginCHROMIUM(const char* category_name,
6889 const char* trace_name) {
6890 GPU_CLIENT_SINGLE_THREAD_CHECK();
6891 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
6892 << category_name << ", " << trace_name << ")");
6893 static constexpr size_t kMaxStrLen = 256;
6894 DCHECK_LE(strlen(category_name), kMaxStrLen);
6895 DCHECK_LE(strlen(trace_name), kMaxStrLen);
6896 SetBucketAsCString(kResultBucketId, category_name);
6897 SetBucketAsCString(kResultBucketId + 1, trace_name);
6898 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
6899 helper_->SetBucketSize(kResultBucketId, 0);
6900 helper_->SetBucketSize(kResultBucketId + 1, 0);
6901 current_trace_stack_++;
6902 }
6903
TraceEndCHROMIUM()6904 void GLES2Implementation::TraceEndCHROMIUM() {
6905 GPU_CLIENT_SINGLE_THREAD_CHECK();
6906 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM("
6907 << ")");
6908 if (current_trace_stack_ == 0) {
6909 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
6910 "missing begin trace");
6911 return;
6912 }
6913 helper_->TraceEndCHROMIUM();
6914 current_trace_stack_--;
6915 }
6916
MapBufferCHROMIUM(GLuint target,GLenum access)6917 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
6918 GPU_CLIENT_SINGLE_THREAD_CHECK();
6919 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM(" << target
6920 << ", " << GLES2Util::GetStringEnum(access) << ")");
6921 switch (target) {
6922 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
6923 if (access != GL_READ_ONLY) {
6924 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
6925 return nullptr;
6926 }
6927 break;
6928 default:
6929 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
6930 return nullptr;
6931 }
6932 GLuint buffer_id;
6933 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
6934 if (!buffer_id) {
6935 return nullptr;
6936 }
6937 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
6938 if (!buffer) {
6939 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
6940 return nullptr;
6941 }
6942 if (buffer->mapped()) {
6943 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
6944 return nullptr;
6945 }
6946 // Here we wait for previous transfer operations to be finished.
6947 if (buffer->last_usage_token()) {
6948 helper_->WaitForToken(buffer->last_usage_token());
6949 buffer->set_last_usage_token(0);
6950 }
6951 buffer->set_mapped(true);
6952
6953 GPU_CLIENT_LOG(" returned " << buffer->address());
6954 CheckGLError();
6955 return buffer->address();
6956 }
6957
UnmapBufferCHROMIUM(GLuint target)6958 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
6959 GPU_CLIENT_SINGLE_THREAD_CHECK();
6960 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target
6961 << ")");
6962 GLuint buffer_id;
6963 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
6964 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
6965 }
6966 if (!buffer_id) {
6967 return false;
6968 }
6969 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
6970 if (!buffer) {
6971 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
6972 return false;
6973 }
6974 if (!buffer->mapped()) {
6975 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
6976 return false;
6977 }
6978 buffer->set_mapped(false);
6979 CheckGLError();
6980 return true;
6981 }
6982
ShareGroupTracingGUID() const6983 uint64_t GLES2Implementation::ShareGroupTracingGUID() const {
6984 return share_group_->TracingGUID();
6985 }
6986
SetErrorMessageCallback(base::RepeatingCallback<void (const char *,int32_t)> callback)6987 void GLES2Implementation::SetErrorMessageCallback(
6988 base::RepeatingCallback<void(const char*, int32_t)> callback) {
6989 error_message_callback_ = std::move(callback);
6990 }
6991
ThreadSafeShallowLockDiscardableTexture(uint32_t texture_id)6992 bool GLES2Implementation::ThreadSafeShallowLockDiscardableTexture(
6993 uint32_t texture_id) {
6994 ClientDiscardableTextureManager* manager =
6995 share_group()->discardable_texture_manager();
6996 return manager->TextureIsValid(texture_id) &&
6997 manager->LockTexture(texture_id);
6998 }
6999
CompleteLockDiscardableTexureOnContextThread(uint32_t texture_id)7000 void GLES2Implementation::CompleteLockDiscardableTexureOnContextThread(
7001 uint32_t texture_id) {
7002 helper_->LockDiscardableTextureCHROMIUM(texture_id);
7003 }
7004
ThreadsafeDiscardableTextureIsDeletedForTracing(uint32_t texture_id)7005 bool GLES2Implementation::ThreadsafeDiscardableTextureIsDeletedForTracing(
7006 uint32_t texture_id) {
7007 ClientDiscardableTextureManager* manager =
7008 share_group()->discardable_texture_manager();
7009 return manager->TextureIsDeletedForTracing(texture_id);
7010 }
7011
MapTransferCacheEntry(uint32_t serialized_size)7012 void* GLES2Implementation::MapTransferCacheEntry(uint32_t serialized_size) {
7013 NOTREACHED();
7014 return nullptr;
7015 }
7016
UnmapAndCreateTransferCacheEntry(uint32_t type,uint32_t id)7017 void GLES2Implementation::UnmapAndCreateTransferCacheEntry(uint32_t type,
7018 uint32_t id) {
7019 NOTREACHED();
7020 }
7021
ThreadsafeLockTransferCacheEntry(uint32_t type,uint32_t id)7022 bool GLES2Implementation::ThreadsafeLockTransferCacheEntry(uint32_t type,
7023 uint32_t id) {
7024 NOTREACHED();
7025 return false;
7026 }
7027
UnlockTransferCacheEntries(const std::vector<std::pair<uint32_t,uint32_t>> & entries)7028 void GLES2Implementation::UnlockTransferCacheEntries(
7029 const std::vector<std::pair<uint32_t, uint32_t>>& entries) {
7030 NOTREACHED();
7031 }
7032
DeleteTransferCacheEntry(uint32_t type,uint32_t id)7033 void GLES2Implementation::DeleteTransferCacheEntry(uint32_t type, uint32_t id) {
7034 NOTREACHED();
7035 }
7036
GetTransferBufferFreeSize() const7037 unsigned int GLES2Implementation::GetTransferBufferFreeSize() const {
7038 NOTREACHED();
7039 return 0;
7040 }
7041
IsJpegDecodeAccelerationSupported() const7042 bool GLES2Implementation::IsJpegDecodeAccelerationSupported() const {
7043 NOTREACHED();
7044 return false;
7045 }
7046
IsWebPDecodeAccelerationSupported() const7047 bool GLES2Implementation::IsWebPDecodeAccelerationSupported() const {
7048 NOTREACHED();
7049 return false;
7050 }
7051
CanDecodeWithHardwareAcceleration(const cc::ImageHeaderMetadata * image_metadata) const7052 bool GLES2Implementation::CanDecodeWithHardwareAcceleration(
7053 const cc::ImageHeaderMetadata* image_metadata) const {
7054 NOTREACHED();
7055 return false;
7056 }
7057
7058 namespace {
7059
CreateImageValidInternalFormat(GLenum internalformat,const Capabilities & capabilities)7060 bool CreateImageValidInternalFormat(GLenum internalformat,
7061 const Capabilities& capabilities) {
7062 switch (internalformat) {
7063 case GL_R16_EXT:
7064 return capabilities.texture_norm16;
7065 case GL_RGB10_A2_EXT:
7066 return capabilities.image_ar30 || capabilities.image_ab30;
7067 case GL_RGB_YCBCR_P010_CHROMIUM:
7068 return capabilities.image_ycbcr_p010;
7069 case GL_RED:
7070 case GL_RG_EXT:
7071 case GL_RGB:
7072 case GL_RGBA:
7073 case GL_RGB_YCBCR_422_CHROMIUM:
7074 case GL_RGB_YCBCR_420V_CHROMIUM:
7075 case GL_RGB_YCRCB_420_CHROMIUM:
7076 case GL_BGRA_EXT:
7077 return true;
7078 default:
7079 return false;
7080 }
7081 }
7082
7083 } // namespace
7084
CreateImageCHROMIUMHelper(ClientBuffer buffer,GLsizei width,GLsizei height,GLenum internalformat)7085 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
7086 GLsizei width,
7087 GLsizei height,
7088 GLenum internalformat) {
7089 if (width <= 0) {
7090 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
7091 return 0;
7092 }
7093
7094 if (height <= 0) {
7095 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
7096 return 0;
7097 }
7098
7099 if (!CreateImageValidInternalFormat(internalformat, capabilities_)) {
7100 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
7101 return 0;
7102 }
7103
7104 // CreateImage creates a fence sync so we must flush first to ensure all
7105 // previously created fence syncs are flushed first.
7106 FlushHelper();
7107
7108 int32_t image_id = gpu_control_->CreateImage(buffer, width, height);
7109 if (image_id < 0) {
7110 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
7111 return 0;
7112 }
7113 return image_id;
7114 }
7115
CreateImageCHROMIUM(ClientBuffer buffer,GLsizei width,GLsizei height,GLenum internalformat)7116 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
7117 GLsizei width,
7118 GLsizei height,
7119 GLenum internalformat) {
7120 GPU_CLIENT_SINGLE_THREAD_CHECK();
7121 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
7122 << ", " << height << ", "
7123 << GLES2Util::GetStringImageInternalFormat(internalformat)
7124 << ")");
7125 GLuint image_id =
7126 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
7127 CheckGLError();
7128 return image_id;
7129 }
7130
DestroyImageCHROMIUMHelper(GLuint image_id)7131 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
7132 // Flush the command stream to make sure all pending commands
7133 // that may refer to the image_id are executed on the service side.
7134 helper_->CommandBufferHelper::Flush();
7135 gpu_control_->DestroyImage(image_id);
7136 }
7137
DestroyImageCHROMIUM(GLuint image_id)7138 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
7139 GPU_CLIENT_SINGLE_THREAD_CHECK();
7140 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
7141 << image_id << ")");
7142 DestroyImageCHROMIUMHelper(image_id);
7143 CheckGLError();
7144 }
7145
ValidateSize(const char * func,GLsizeiptr size)7146 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
7147 if (size < 0) {
7148 SetGLError(GL_INVALID_VALUE, func, "size < 0");
7149 return false;
7150 }
7151 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
7152 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
7153 return false;
7154 }
7155 return true;
7156 }
7157
ValidateOffset(const char * func,GLintptr offset)7158 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
7159 if (offset < 0) {
7160 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
7161 return false;
7162 }
7163 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
7164 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
7165 return false;
7166 }
7167 return true;
7168 }
7169
GetSamplerParameterfvHelper(GLuint,GLenum,GLfloat *)7170 bool GLES2Implementation::GetSamplerParameterfvHelper(GLuint /* sampler */,
7171 GLenum /* pname */,
7172 GLfloat* /* params */) {
7173 // TODO(zmo): Implement client side caching.
7174 return false;
7175 }
7176
GetSamplerParameterivHelper(GLuint,GLenum,GLint *)7177 bool GLES2Implementation::GetSamplerParameterivHelper(GLuint /* sampler */,
7178 GLenum /* pname */,
7179 GLint* /* params */) {
7180 // TODO(zmo): Implement client side caching.
7181 return false;
7182 }
7183
PackStringsToBucket(GLsizei count,const char * const * str,const GLint * length,const char * func_name)7184 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
7185 const char* const* str,
7186 const GLint* length,
7187 const char* func_name) {
7188 DCHECK_LE(0, count);
7189 // Compute the total size.
7190 base::CheckedNumeric<uint32_t> total_size = count;
7191 total_size += 1;
7192 total_size *= sizeof(GLint);
7193 uint32_t header_size = 0;
7194 if (!total_size.AssignIfValid(&header_size)) {
7195 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
7196 return false;
7197 }
7198 std::vector<GLint> header(count + 1);
7199 header[0] = static_cast<GLint>(count);
7200 for (GLsizei ii = 0; ii < count; ++ii) {
7201 GLint len = 0;
7202 if (str[ii]) {
7203 len = (length && length[ii] >= 0)
7204 ? length[ii]
7205 : base::checked_cast<GLint>(strlen(str[ii]));
7206 }
7207 total_size += len;
7208 total_size += 1; // NULL at the end of each char array.
7209 header[ii + 1] = len;
7210 }
7211 // Pack data into a bucket on the service.
7212 uint32_t validated_size = 0;
7213 if (!total_size.AssignIfValid(&validated_size)) {
7214 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
7215 return false;
7216 }
7217 helper_->SetBucketSize(kResultBucketId, validated_size);
7218 uint32_t offset = 0;
7219 for (GLsizei ii = 0; ii <= count; ++ii) {
7220 const char* src =
7221 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
7222 uint32_t size = (ii == 0) ? header_size : header[ii];
7223 if (ii > 0) {
7224 size += 1; // NULL in the end.
7225 }
7226 while (size) {
7227 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
7228 if (!buffer.valid() || buffer.size() == 0) {
7229 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
7230 return false;
7231 }
7232 uint32_t copy_size = buffer.size();
7233 if (ii > 0 && buffer.size() == size)
7234 --copy_size;
7235 if (copy_size)
7236 memcpy(buffer.address(), src, copy_size);
7237 if (copy_size < buffer.size()) {
7238 // Append NULL in the end.
7239 DCHECK(copy_size + 1 == buffer.size());
7240 char* str = reinterpret_cast<char*>(buffer.address());
7241 str[copy_size] = 0;
7242 }
7243 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
7244 buffer.shm_id(), buffer.offset());
7245 offset += buffer.size();
7246 src += buffer.size();
7247 size -= buffer.size();
7248 }
7249 }
7250 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
7251 return true;
7252 }
7253
UniformBlockBinding(GLuint program,GLuint index,GLuint binding)7254 void GLES2Implementation::UniformBlockBinding(GLuint program,
7255 GLuint index,
7256 GLuint binding) {
7257 GPU_CLIENT_SINGLE_THREAD_CHECK();
7258 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
7259 << ", " << index << ", " << binding << ")");
7260 share_group_->program_info_manager()->UniformBlockBinding(this, program,
7261 index, binding);
7262 helper_->UniformBlockBinding(program, index, binding);
7263 CheckGLError();
7264 }
7265
ClientWaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)7266 GLenum GLES2Implementation::ClientWaitSync(GLsync sync,
7267 GLbitfield flags,
7268 GLuint64 timeout) {
7269 GPU_CLIENT_SINGLE_THREAD_CHECK();
7270 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync << ", "
7271 << flags << ", " << timeout << ")");
7272 typedef cmds::ClientWaitSync::Result Result;
7273 auto result = GetResultAs<Result>();
7274 if (!result) {
7275 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
7276 return GL_WAIT_FAILED;
7277 }
7278 *result = GL_WAIT_FAILED;
7279 helper_->ClientWaitSync(ToGLuint(sync), flags, timeout, GetResultShmId(),
7280 result.offset());
7281 WaitForCmd();
7282 GPU_CLIENT_LOG("returned " << *result);
7283 CheckGLError();
7284 return *result;
7285 }
7286
CopyBufferSubData(GLenum readtarget,GLenum writetarget,GLintptr readoffset,GLintptr writeoffset,GLsizeiptr size)7287 void GLES2Implementation::CopyBufferSubData(GLenum readtarget,
7288 GLenum writetarget,
7289 GLintptr readoffset,
7290 GLintptr writeoffset,
7291 GLsizeiptr size) {
7292 GPU_CLIENT_SINGLE_THREAD_CHECK();
7293 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCopyBufferSubData("
7294 << GLES2Util::GetStringBufferTarget(readtarget) << ", "
7295 << GLES2Util::GetStringBufferTarget(writetarget) << ", "
7296 << readoffset << ", " << writeoffset << ", " << size
7297 << ")");
7298 if (readoffset < 0) {
7299 SetGLError(GL_INVALID_VALUE, "glCopyBufferSubData", "readoffset < 0");
7300 return;
7301 }
7302 if (writeoffset < 0) {
7303 SetGLError(GL_INVALID_VALUE, "glCopyBufferSubData", "writeoffset < 0");
7304 return;
7305 }
7306 if (size < 0) {
7307 SetGLError(GL_INVALID_VALUE, "glCopyBufferSubData", "size < 0");
7308 return;
7309 }
7310 helper_->CopyBufferSubData(readtarget, writetarget, readoffset, writeoffset,
7311 size);
7312 InvalidateReadbackBufferShadowDataCHROMIUM(GetBoundBufferHelper(writetarget));
7313 CheckGLError();
7314 }
7315
WaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)7316 void GLES2Implementation::WaitSync(GLsync sync,
7317 GLbitfield flags,
7318 GLuint64 timeout) {
7319 GPU_CLIENT_SINGLE_THREAD_CHECK();
7320 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
7321 << flags << ", " << timeout << ")");
7322 helper_->WaitSync(ToGLuint(sync), flags, timeout);
7323 CheckGLError();
7324 }
7325
GetInternalformativ(GLenum target,GLenum format,GLenum pname,GLsizei buf_size,GLint * params)7326 void GLES2Implementation::GetInternalformativ(GLenum target,
7327 GLenum format,
7328 GLenum pname,
7329 GLsizei buf_size,
7330 GLint* params) {
7331 GPU_CLIENT_SINGLE_THREAD_CHECK();
7332 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
7333 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
7334 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
7335 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
7336 << GLES2Util::GetStringInternalFormatParameter(pname)
7337 << ", " << buf_size << ", "
7338 << static_cast<const void*>(params) << ")");
7339 if (buf_size < 0) {
7340 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
7341 return;
7342 }
7343 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
7344 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
7345 return;
7346 }
7347 typedef cmds::GetInternalformativ::Result Result;
7348 auto result = GetResultAs<Result>();
7349 if (!result) {
7350 return;
7351 }
7352 result->SetNumResults(0);
7353 helper_->GetInternalformativ(target, format, pname, GetResultShmId(),
7354 result.offset());
7355 WaitForCmd();
7356 GPU_CLIENT_LOG_CODE_BLOCK({
7357 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
7358 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
7359 }
7360 });
7361 if (buf_size > 0 && params) {
7362 GLint* data = result->GetData();
7363 if (buf_size >= result->GetNumResults()) {
7364 buf_size = result->GetNumResults();
7365 }
7366 for (GLsizei ii = 0; ii < buf_size; ++ii) {
7367 params[ii] = data[ii];
7368 }
7369 }
7370 CheckGLError();
7371 }
7372
InitializeDiscardableTextureCHROMIUM(GLuint texture_id)7373 void GLES2Implementation::InitializeDiscardableTextureCHROMIUM(
7374 GLuint texture_id) {
7375 ClientDiscardableTextureManager* manager =
7376 share_group()->discardable_texture_manager();
7377 if (manager->TextureIsValid(texture_id)) {
7378 SetGLError(GL_INVALID_VALUE, "glInitializeDiscardableTextureCHROMIUM",
7379 "Texture ID already initialized");
7380 return;
7381 }
7382 ClientDiscardableHandle handle =
7383 manager->InitializeTexture(helper_->command_buffer(), texture_id);
7384 if (!handle.IsValid())
7385 return;
7386
7387 helper_->InitializeDiscardableTextureCHROMIUM(texture_id, handle.shm_id(),
7388 handle.byte_offset());
7389 }
7390
UnlockDiscardableTextureCHROMIUM(GLuint texture_id)7391 void GLES2Implementation::UnlockDiscardableTextureCHROMIUM(GLuint texture_id) {
7392 ClientDiscardableTextureManager* manager =
7393 share_group()->discardable_texture_manager();
7394 if (!manager->TextureIsValid(texture_id)) {
7395 SetGLError(GL_INVALID_VALUE, "glUnlockDiscardableTextureCHROMIUM",
7396 "Texture ID not initialized");
7397 return;
7398 }
7399
7400 // |should_unbind_texture| will be set to true if the texture has been fully
7401 // unlocked. In this case, ensure the texture is unbound.
7402 bool should_unbind_texture = false;
7403 manager->UnlockTexture(texture_id, &should_unbind_texture);
7404 if (should_unbind_texture)
7405 UnbindTexturesHelper(1, &texture_id);
7406
7407 helper_->UnlockDiscardableTextureCHROMIUM(texture_id);
7408 }
7409
LockDiscardableTextureCHROMIUM(GLuint texture_id)7410 bool GLES2Implementation::LockDiscardableTextureCHROMIUM(GLuint texture_id) {
7411 ClientDiscardableTextureManager* manager =
7412 share_group()->discardable_texture_manager();
7413 if (!manager->TextureIsValid(texture_id)) {
7414 SetGLError(GL_INVALID_VALUE, "glLockDiscardableTextureCHROMIUM",
7415 "Texture ID not initialized");
7416 return false;
7417 }
7418 if (!manager->LockTexture(texture_id)) {
7419 // Failure to lock means that this texture has been deleted on the service
7420 // side. Delete it here as well.
7421 DeleteTexturesHelper(1, &texture_id);
7422 return false;
7423 }
7424 helper_->LockDiscardableTextureCHROMIUM(texture_id);
7425 return true;
7426 }
7427
UpdateCachedExtensionsIfNeeded()7428 void GLES2Implementation::UpdateCachedExtensionsIfNeeded() {
7429 if (cached_extension_string_) {
7430 return;
7431 }
7432 GetStringHelper(GL_EXTENSIONS);
7433 }
7434
InvalidateCachedExtensions()7435 void GLES2Implementation::InvalidateCachedExtensions() {
7436 cached_extension_string_ = nullptr;
7437 cached_extensions_.clear();
7438 }
7439
Viewport(GLint x,GLint y,GLsizei width,GLsizei height)7440 void GLES2Implementation::Viewport(GLint x,
7441 GLint y,
7442 GLsizei width,
7443 GLsizei height) {
7444 GPU_CLIENT_SINGLE_THREAD_CHECK();
7445 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glViewport(" << x << ", " << y
7446 << ", " << width << ", " << height << ")");
7447 if (width < 0 || height < 0) {
7448 SetGLError(GL_INVALID_VALUE, "glViewport", "negative width/height");
7449 return;
7450 }
7451 state_.SetViewport(x, y, width, height);
7452 helper_->Viewport(x, y, width, height);
7453 CheckGLError();
7454 }
7455
IssueBeginQuery(GLenum target,GLuint id,uint32_t sync_data_shm_id,uint32_t sync_data_shm_offset)7456 void GLES2Implementation::IssueBeginQuery(GLenum target,
7457 GLuint id,
7458 uint32_t sync_data_shm_id,
7459 uint32_t sync_data_shm_offset) {
7460 helper_->BeginQueryEXT(target, id, sync_data_shm_id, sync_data_shm_offset);
7461 }
7462
IssueEndQuery(GLenum target,GLuint submit_count)7463 void GLES2Implementation::IssueEndQuery(GLenum target, GLuint submit_count) {
7464 helper_->EndQueryEXT(target, submit_count);
7465 }
7466
IssueQueryCounter(GLuint id,GLenum target,uint32_t sync_data_shm_id,uint32_t sync_data_shm_offset,GLuint submit_count)7467 void GLES2Implementation::IssueQueryCounter(GLuint id,
7468 GLenum target,
7469 uint32_t sync_data_shm_id,
7470 uint32_t sync_data_shm_offset,
7471 GLuint submit_count) {
7472 helper_->QueryCounterEXT(id, target, sync_data_shm_id, sync_data_shm_offset,
7473 submit_count);
7474 }
7475
IssueSetDisjointValueSync(uint32_t sync_data_shm_id,uint32_t sync_data_shm_offset)7476 void GLES2Implementation::IssueSetDisjointValueSync(
7477 uint32_t sync_data_shm_id,
7478 uint32_t sync_data_shm_offset) {
7479 helper_->SetDisjointValueSyncCHROMIUM(sync_data_shm_id, sync_data_shm_offset);
7480 }
7481
GetClientSideGLError()7482 GLenum GLES2Implementation::GetClientSideGLError() {
7483 if (error_bits_ == 0) {
7484 return GL_NO_ERROR;
7485 }
7486
7487 GLenum error = GL_NO_ERROR;
7488 for (uint32_t mask = 1; mask != 0; mask = mask << 1) {
7489 if ((error_bits_ & mask) != 0) {
7490 error = GLES2Util::GLErrorBitToGLError(mask);
7491 break;
7492 }
7493 }
7494 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
7495 return error;
7496 }
7497
cmd_buffer_helper()7498 CommandBufferHelper* GLES2Implementation::cmd_buffer_helper() {
7499 return helper_;
7500 }
7501
command_buffer() const7502 CommandBuffer* GLES2Implementation::command_buffer() const {
7503 return helper_->command_buffer();
7504 }
7505
SetActiveURLCHROMIUM(const char * url)7506 void GLES2Implementation::SetActiveURLCHROMIUM(const char* url) {
7507 DCHECK(url);
7508 GPU_CLIENT_SINGLE_THREAD_CHECK();
7509 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSetActiveURLCHROMIUM(" << url);
7510
7511 if (last_active_url_ == url)
7512 return;
7513
7514 last_active_url_ = url;
7515 static constexpr uint32_t kMaxStrLen = 1024;
7516 size_t len = strlen(url);
7517 if (len == 0)
7518 return;
7519
7520 SetBucketContents(kResultBucketId, url,
7521 base::CheckMin(len, kMaxStrLen).ValueOrDie());
7522 helper_->SetActiveURLCHROMIUM(kResultBucketId);
7523 helper_->SetBucketSize(kResultBucketId, 0);
7524 }
7525
7526 // Include the auto-generated part of this file. We split this because it means
7527 // we can easily edit the non-auto generated parts right here in this file
7528 // instead of having to edit some template or the code generator.
7529 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
7530
7531 } // namespace gles2
7532 } // namespace gpu
7533