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