blob: dd86768eea84035328fbbd4194377d9b234752a2 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/webgl/WebGL2RenderingContextBase.h"
#include <memory>
#include "bindings/modules/v8/WebGLAny.h"
#include "core/html/HTMLImageElement.h"
#include "core/html/canvas/HTMLCanvasElement.h"
#include "core/html/canvas/ImageData.h"
#include "core/html/media/HTMLVideoElement.h"
#include "core/imagebitmap/ImageBitmap.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "modules/webgl/WebGLActiveInfo.h"
#include "modules/webgl/WebGLBuffer.h"
#include "modules/webgl/WebGLFenceSync.h"
#include "modules/webgl/WebGLFramebuffer.h"
#include "modules/webgl/WebGLGetBufferSubDataAsync.h"
#include "modules/webgl/WebGLProgram.h"
#include "modules/webgl/WebGLQuery.h"
#include "modules/webgl/WebGLRenderbuffer.h"
#include "modules/webgl/WebGLSampler.h"
#include "modules/webgl/WebGLSync.h"
#include "modules/webgl/WebGLTexture.h"
#include "modules/webgl/WebGLTransformFeedback.h"
#include "modules/webgl/WebGLUniformLocation.h"
#include "modules/webgl/WebGLVertexArrayObject.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/text/WTFString.h"
#include "public/platform/WebGraphicsContext3DProvider.h"
using WTF::String;
namespace blink {
namespace {
const GLuint64 kMaxClientWaitTimeout = 0u;
// TODO(kainino): Change outByteLength to GLuint and change the associated
// range checking (and all uses) - overflow becomes possible in cases below
bool ValidateSubSourceAndGetData(DOMArrayBufferView* view,
GLuint sub_offset,
GLuint sub_length,
void** out_base_address,
long long* out_byte_length) {
// This is guaranteed to be non-null by DOM.
DCHECK(view);
size_t type_size = view->TypeSize();
DCHECK_GE(8u, type_size);
long long byte_length = 0;
if (sub_length) {
// type size is at most 8, so no overflow.
byte_length = sub_length * type_size;
}
long long byte_offset = 0;
if (sub_offset) {
// type size is at most 8, so no overflow.
byte_offset = sub_offset * type_size;
}
CheckedNumeric<long long> total = byte_offset;
total += byte_length;
if (!total.IsValid() || total.ValueOrDie() > view->byteLength()) {
return false;
}
if (!byte_length) {
byte_length = view->byteLength() - byte_offset;
}
uint8_t* data = static_cast<uint8_t*>(view->BaseAddressMaybeShared());
data += byte_offset;
*out_base_address = data;
*out_byte_length = byte_length;
return true;
}
} // namespace
// These enums are from manual pages for glTexStorage2D/glTexStorage3D.
const GLenum kSupportedInternalFormatsStorage[] = {
GL_R8,
GL_R8_SNORM,
GL_R16F,
GL_R32F,
GL_R8UI,
GL_R8I,
GL_R16UI,
GL_R16I,
GL_R32UI,
GL_R32I,
GL_RG8,
GL_RG8_SNORM,
GL_RG16F,
GL_RG32F,
GL_RG8UI,
GL_RG8I,
GL_RG16UI,
GL_RG16I,
GL_RG32UI,
GL_RG32I,
GL_RGB8,
GL_SRGB8,
GL_RGB565,
GL_RGB8_SNORM,
GL_R11F_G11F_B10F,
GL_RGB9_E5,
GL_RGB16F,
GL_RGB32F,
GL_RGB8UI,
GL_RGB8I,
GL_RGB16UI,
GL_RGB16I,
GL_RGB32UI,
GL_RGB32I,
GL_RGBA8,
GL_SRGB8_ALPHA8,
GL_RGBA8_SNORM,
GL_RGB5_A1,
GL_RGBA4,
GL_RGB10_A2,
GL_RGBA16F,
GL_RGBA32F,
GL_RGBA8UI,
GL_RGBA8I,
GL_RGB10_A2UI,
GL_RGBA16UI,
GL_RGBA16I,
GL_RGBA32UI,
GL_RGBA32I,
GL_DEPTH_COMPONENT16,
GL_DEPTH_COMPONENT24,
GL_DEPTH_COMPONENT32F,
GL_DEPTH24_STENCIL8,
GL_DEPTH32F_STENCIL8,
};
WebGL2RenderingContextBase::WebGL2RenderingContextBase(
CanvasRenderingContextHost* host,
std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
bool using_gpu_compositing,
const CanvasContextCreationAttributes& requested_attributes)
: WebGLRenderingContextBase(host,
std::move(context_provider),
using_gpu_compositing,
requested_attributes,
2) {
supported_internal_formats_storage_.insert(
kSupportedInternalFormatsStorage,
kSupportedInternalFormatsStorage +
WTF_ARRAY_LENGTH(kSupportedInternalFormatsStorage));
}
void WebGL2RenderingContextBase::DestroyContext() {
for (auto& callback : get_buffer_sub_data_async_callbacks_) {
callback->Destroy();
}
get_buffer_sub_data_async_callbacks_.clear();
WebGLRenderingContextBase::DestroyContext();
}
void WebGL2RenderingContextBase::InitializeNewContext() {
DCHECK(!isContextLost());
DCHECK(GetDrawingBuffer());
read_framebuffer_binding_ = nullptr;
bound_copy_read_buffer_ = nullptr;
bound_copy_write_buffer_ = nullptr;
bound_pixel_pack_buffer_ = nullptr;
bound_pixel_unpack_buffer_ = nullptr;
bound_uniform_buffer_ = nullptr;
current_boolean_occlusion_query_ = nullptr;
current_transform_feedback_primitives_written_query_ = nullptr;
current_elapsed_query_ = nullptr;
GLint num_combined_texture_image_units = 0;
ContextGL()->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
&num_combined_texture_image_units);
sampler_units_.clear();
sampler_units_.resize(num_combined_texture_image_units);
max_transform_feedback_separate_attribs_ = 0;
// This must be queried before instantiating any transform feedback
// objects.
ContextGL()->GetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&max_transform_feedback_separate_attribs_);
// Create a default transform feedback object so there is a place to
// hold any bound buffers.
default_transform_feedback_ = WebGLTransformFeedback::Create(
this, WebGLTransformFeedback::TFTypeDefault);
transform_feedback_binding_ = default_transform_feedback_;
GLint max_uniform_buffer_bindings = 0;
ContextGL()->GetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
&max_uniform_buffer_bindings);
bound_indexed_uniform_buffers_.clear();
bound_indexed_uniform_buffers_.resize(max_uniform_buffer_bindings);
max_bound_uniform_buffer_index_ = 0;
pack_row_length_ = 0;
pack_skip_pixels_ = 0;
pack_skip_rows_ = 0;
unpack_row_length_ = 0;
unpack_image_height_ = 0;
unpack_skip_pixels_ = 0;
unpack_skip_rows_ = 0;
unpack_skip_images_ = 0;
WebGLRenderingContextBase::InitializeNewContext();
}
void WebGL2RenderingContextBase::bufferData(
GLenum target,
MaybeShared<DOMArrayBufferView> src_data,
GLenum usage,
GLuint src_offset,
GLuint length) {
if (isContextLost())
return;
void* sub_base_address = nullptr;
long long sub_byte_length = 0;
if (!ValidateSubSourceAndGetData(src_data.View(), src_offset, length,
&sub_base_address, &sub_byte_length)) {
SynthesizeGLError(GL_INVALID_VALUE, "bufferData",
"srcOffset + length too large");
return;
}
BufferDataImpl(target, sub_byte_length, sub_base_address, usage);
}
void WebGL2RenderingContextBase::bufferData(GLenum target,
long long size,
GLenum usage) {
WebGLRenderingContextBase::bufferData(target, size, usage);
}
void WebGL2RenderingContextBase::bufferData(GLenum target,
DOMArrayBuffer* data,
GLenum usage) {
WebGLRenderingContextBase::bufferData(target, data, usage);
}
void WebGL2RenderingContextBase::bufferData(
GLenum target,
MaybeShared<DOMArrayBufferView> data,
GLenum usage) {
WebGLRenderingContextBase::bufferData(target, data, usage);
}
void WebGL2RenderingContextBase::bufferSubData(
GLenum target,
GLintptr dst_byte_offset,
MaybeShared<DOMArrayBufferView> src_data,
GLuint src_offset,
GLuint length) {
if (isContextLost())
return;
void* sub_base_address = nullptr;
long long sub_byte_length = 0;
if (!ValidateSubSourceAndGetData(src_data.View(), src_offset, length,
&sub_base_address, &sub_byte_length)) {
SynthesizeGLError(GL_INVALID_VALUE, "bufferSubData",
"srcOffset + length too large");
return;
}
BufferSubDataImpl(target, dst_byte_offset, sub_byte_length, sub_base_address);
}
void WebGL2RenderingContextBase::bufferSubData(GLenum target,
long long offset,
DOMArrayBuffer* data) {
WebGLRenderingContextBase::bufferSubData(target, offset, data);
}
void WebGL2RenderingContextBase::bufferSubData(
GLenum target,
long long offset,
const FlexibleArrayBufferView& data) {
WebGLRenderingContextBase::bufferSubData(target, offset, data);
}
void WebGL2RenderingContextBase::copyBufferSubData(GLenum read_target,
GLenum write_target,
long long read_offset,
long long write_offset,
long long size) {
if (isContextLost())
return;
if (!ValidateValueFitNonNegInt32("copyBufferSubData", "readOffset",
read_offset) ||
!ValidateValueFitNonNegInt32("copyBufferSubData", "writeOffset",
write_offset) ||
!ValidateValueFitNonNegInt32("copyBufferSubData", "size", size)) {
return;
}
WebGLBuffer* read_buffer =
ValidateBufferDataTarget("copyBufferSubData", read_target);
if (!read_buffer)
return;
WebGLBuffer* write_buffer =
ValidateBufferDataTarget("copyBufferSubData", write_target);
if (!write_buffer)
return;
if (read_offset + size > read_buffer->GetSize() ||
write_offset + size > write_buffer->GetSize()) {
SynthesizeGLError(GL_INVALID_VALUE, "copyBufferSubData", "buffer overflow");
return;
}
if ((write_buffer->GetInitialTarget() == GL_ELEMENT_ARRAY_BUFFER &&
read_buffer->GetInitialTarget() != GL_ELEMENT_ARRAY_BUFFER) ||
(write_buffer->GetInitialTarget() != GL_ELEMENT_ARRAY_BUFFER &&
read_buffer->GetInitialTarget() == GL_ELEMENT_ARRAY_BUFFER)) {
SynthesizeGLError(GL_INVALID_OPERATION, "copyBufferSubData",
"Cannot copy into an element buffer destination from a "
"non-element buffer source");
return;
}
if (write_buffer->GetInitialTarget() == 0)
write_buffer->SetInitialTarget(read_buffer->GetInitialTarget());
ContextGL()->CopyBufferSubData(
read_target, write_target, static_cast<GLintptr>(read_offset),
static_cast<GLintptr>(write_offset), static_cast<GLsizeiptr>(size));
}
void WebGL2RenderingContextBase::getBufferSubData(
GLenum target,
long long src_byte_offset,
MaybeShared<DOMArrayBufferView> dst_data,
GLuint dst_offset,
GLuint length) {
WebGLBuffer* source_buffer = nullptr;
void* destination_data_ptr = nullptr;
long long destination_byte_length = 0;
const char* message = ValidateGetBufferSubData(
__FUNCTION__, target, src_byte_offset, dst_data.View(), dst_offset,
length, &source_buffer, &destination_data_ptr, &destination_byte_length);
if (message) {
// If there was a GL error, it was already synthesized in
// validateGetBufferSubData, so it's not done here.
return;
}
// If the length of the copy is zero, this is a no-op.
if (!destination_byte_length) {
return;
}
void* mapped_data = ContextGL()->MapBufferRange(
target, static_cast<GLintptr>(src_byte_offset), destination_byte_length,
GL_MAP_READ_BIT);
if (!mapped_data)
return;
memcpy(destination_data_ptr, mapped_data, destination_byte_length);
ContextGL()->UnmapBuffer(target);
}
void WebGL2RenderingContextBase::RegisterGetBufferSubDataAsyncCallback(
WebGLGetBufferSubDataAsyncCallback* callback) {
get_buffer_sub_data_async_callbacks_.insert(callback);
}
void WebGL2RenderingContextBase::UnregisterGetBufferSubDataAsyncCallback(
WebGLGetBufferSubDataAsyncCallback* callback) {
get_buffer_sub_data_async_callbacks_.erase(callback);
}
void WebGL2RenderingContextBase::blitFramebuffer(GLint src_x0,
GLint src_y0,
GLint src_x1,
GLint src_y1,
GLint dst_x0,
GLint dst_y0,
GLint dst_x1,
GLint dst_y1,
GLbitfield mask,
GLenum filter) {
if (isContextLost())
return;
bool user_framebuffer_bound = GetFramebufferBinding(GL_DRAW_FRAMEBUFFER);
DrawingBuffer::ScopedRGBEmulationForBlitFramebuffer emulation(
GetDrawingBuffer(), user_framebuffer_bound);
ContextGL()->BlitFramebufferCHROMIUM(src_x0, src_y0, src_x1, src_y1, dst_x0,
dst_y0, dst_x1, dst_y1, mask, filter);
MarkContextChanged(kCanvasChanged);
}
bool WebGL2RenderingContextBase::ValidateTexFuncLayer(const char* function_name,
GLenum tex_target,
GLint layer) {
if (layer < 0) {
SynthesizeGLError(GL_INVALID_VALUE, function_name, "layer out of range");
return false;
}
switch (tex_target) {
case GL_TEXTURE_3D:
if (layer > max3d_texture_size_ - 1) {
SynthesizeGLError(GL_INVALID_VALUE, function_name,
"layer out of range");
return false;
}
break;
case GL_TEXTURE_2D_ARRAY:
if (layer > max_array_texture_layers_ - 1) {
SynthesizeGLError(GL_INVALID_VALUE, function_name,
"layer out of range");
return false;
}
break;
default:
NOTREACHED();
return false;
}
return true;
}
void WebGL2RenderingContextBase::framebufferTextureLayer(GLenum target,
GLenum attachment,
WebGLTexture* texture,
GLint level,
GLint layer) {
if (isContextLost() || !ValidateFramebufferFuncParameters(
"framebufferTextureLayer", target, attachment))
return;
if (texture && !texture->Validate(ContextGroup(), this)) {
SynthesizeGLError(GL_INVALID_VALUE, "framebufferTextureLayer",
"no texture or texture not from this context");
return;
}
GLenum textarget = texture ? texture->GetTarget() : 0;
if (texture) {
if (textarget != GL_TEXTURE_3D && textarget != GL_TEXTURE_2D_ARRAY) {
SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTextureLayer",
"invalid texture type");
return;
}
if (!ValidateTexFuncLayer("framebufferTextureLayer", textarget, layer))
return;
if (!ValidateTexFuncLevel("framebufferTextureLayer", textarget, level))
return;
}
WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
if (!framebuffer_binding || !framebuffer_binding->Object()) {
SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTextureLayer",
"no framebuffer bound");
return;
}
// Don't allow modifications to opaque framebuffer attachements.
if (framebuffer_binding && framebuffer_binding->Opaque()) {
SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTextureLayer",
"opaque framebuffer bound");
return;
}
framebuffer_binding->SetAttachmentForBoundFramebuffer(
target, attachment, textarget, texture, level, layer);
ApplyStencilTest();
}
ScriptValue WebGL2RenderingContextBase::getInternalformatParameter(
ScriptState* script_state,
GLenum target,
GLenum internalformat,
GLenum pname) {
if (isContextLost())
return ScriptValue::CreateNull(script_state);
if (target != GL_RENDERBUFFER) {
SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
"invalid target");
return ScriptValue::CreateNull(script_state);
}
switch (internalformat) {
// Renderbuffer doesn't support unsized internal formats,
// though GL_RGB and GL_RGBA are color-renderable.
case GL_RGB:
case GL_RGBA:
// Multisampling is not supported for signed and unsigned integer internal
// formats.
case GL_R8UI:
case GL_R8I:
case GL_R16UI:
case GL_R16I:
case GL_R32UI:
case GL_R32I:
case GL_RG8UI:
case GL_RG8I:
case GL_RG16UI:
case GL_RG16I:
case GL_RG32UI:
case GL_RG32I:
case GL_RGBA8UI:
case GL_RGBA8I:
case GL_RGB10_A2UI:
case GL_RGBA16UI:
case GL_RGBA16I:
case GL_RGBA32UI:
case GL_RGBA32I:
return WebGLAny(script_state, DOMInt32Array::Create(0));
case GL_R8:
case GL_RG8:
case GL_RGB8:
case GL_RGB565:
case GL_RGBA8:
case GL_SRGB8_ALPHA8:
case GL_RGB5_A1:
case GL_RGBA4:
case GL_RGB10_A2:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH24_STENCIL8:
case GL_DEPTH32F_STENCIL8:
case GL_STENCIL_INDEX8:
break;
case GL_R16F:
case GL_RG16F:
case GL_RGBA16F:
case GL_R32F:
case GL_RG32F:
case GL_RGBA32F:
case GL_R11F_G11F_B10F:
if (!ExtensionEnabled(kEXTColorBufferFloatName)) {
SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
"invalid internalformat when EXT_color_buffer_float "
"is not enabled");
return ScriptValue::CreateNull(script_state);
}
break;
default:
SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
"invalid internalformat");
return ScriptValue::CreateNull(script_state);
}
switch (pname) {
case GL_SAMPLES: {
GLint length = -1;
ContextGL()->GetInternalformativ(target, internalformat,
GL_NUM_SAMPLE_COUNTS, 1, &length);
if (length <= 0)
return WebGLAny(script_state, DOMInt32Array::Create(0));
auto values = std::make_unique<GLint[]>(length);
for (GLint ii = 0; ii < length; ++ii)
values[ii] = 0;
ContextGL()->GetInternalformativ(target, internalformat, GL_SAMPLES,
length, values.get());
return WebGLAny(script_state,
DOMInt32Array::Create(values.get(), length));
}
default:
SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
"invalid parameter name");
return ScriptValue::CreateNull(script_state);
}
}
bool WebGL2RenderingContextBase::CheckAndTranslateAttachments(
const char* function_name,
GLenum target,
Vector<GLenum>& attachments) {
if (!ValidateFramebufferTarget(target)) {
SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
return false;
}
WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
DCHECK(framebuffer_binding || GetDrawingBuffer());
if (!framebuffer_binding) {
// For the default framebuffer, translate GL_COLOR/GL_DEPTH/GL_STENCIL.
// The default framebuffer of WebGL is not fb 0, it is an internal fbo.
for (size_t i = 0; i < attachments.size(); ++i) {
switch (attachments[i]) {
case GL_COLOR:
attachments[i] = GL_COLOR_ATTACHMENT0;
break;
case GL_DEPTH:
attachments[i] = GL_DEPTH_ATTACHMENT;
break;
case GL_STENCIL:
attachments[i] = GL_STENCIL_ATTACHMENT;
break;
default:
SynthesizeGLError(GL_INVALID_ENUM, function_name,
"invalid attachment");
return false;
}
}
}
return true;
}
IntRect WebGL2RenderingContextBase::GetTextureSourceSubRectangle(
GLsizei width,
GLsizei height) {
return IntRect(unpack_skip_pixels_, unpack_skip_rows_, width, height);
}
void WebGL2RenderingContextBase::invalidateFramebuffer(
GLenum target,
const Vector<GLenum>& attachments) {
if (isContextLost())
return;
Vector<GLenum> translated_attachments = attachments;
if (!CheckAndTranslateAttachments("invalidateFramebuffer", target,
translated_attachments))
return;
ContextGL()->InvalidateFramebuffer(target, translated_attachments.size(),
translated_attachments.data());
}
void WebGL2RenderingContextBase::invalidateSubFramebuffer(
GLenum target,
const Vector<GLenum>& attachments,
GLint x,
GLint y,
GLsizei width,
GLsizei height) {
if (isContextLost())
return;
Vector<GLenum> translated_attachments = attachments;
if (!CheckAndTranslateAttachments("invalidateSubFramebuffer", target,
translated_attachments))
return;
ContextGL()->InvalidateSubFramebuffer(target, translated_attachments.size(),
translated_attachments.data(), x, y,
width, height);
}
void WebGL2RenderingContextBase::readBuffer(GLenum mode) {
if (isContextLost())
return;
switch (mode) {
case GL_BACK:
case GL_NONE:
case GL_COLOR_ATTACHMENT0:
break;
default:
if (mode > GL_COLOR_ATTACHMENT0 &&
mode <
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + MaxColorAttachments()))
break;
SynthesizeGLError(GL_INVALID_ENUM, "readBuffer", "invalid read buffer");
return;
}
WebGLFramebuffer* read_framebuffer_binding =
GetFramebufferBinding(GL_READ_FRAMEBUFFER);
if (!read_framebuffer_binding) {
DCHECK(GetDrawingBuffer());
if (mode != GL_BACK && mode != GL_NONE) {
SynthesizeGLError(GL_INVALID_OPERATION, "readBuffer",
"invalid read buffer");
return;
}
read_buffer_of_default_framebuffer_ = mode;
// translate GL_BACK to GL_COLOR_ATTACHMENT0, because the default
// framebuffer for WebGL is not fb 0, it is an internal fbo.
if (mode == GL_BACK)
mode = GL_COLOR_ATTACHMENT0;
} else {
if (mode == GL_BACK) {
SynthesizeGLError(GL_INVALID_OPERATION, "readBuffer",
"invalid read buffer");
return;
}
read_framebuffer_binding->ReadBuffer(mode);
}
ContextGL()->ReadBuffer(mode);
}
void WebGL2RenderingContextBase::pixelStorei(GLenum pname, GLint param) {
if (isContextLost())
return;
if (param < 0) {
SynthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "negative value");
return;
}
switch (pname) {
case GL_PACK_ROW_LENGTH:
pack_row_length_ = param;
break;
case GL_PACK_SKIP_PIXELS:
pack_skip_pixels_ = param;
break;
case GL_PACK_SKIP_ROWS:
pack_skip_rows_ = param;
break;
case GL_UNPACK_ROW_LENGTH:
unpack_row_length_ = param;
break;
case GL_UNPACK_IMAGE_HEIGHT:
unpack_image_height_ = param;
break;
case GL_UNPACK_SKIP_PIXELS:
unpack_skip_pixels_ = param;
break;
case GL_UNPACK_SKIP_ROWS:
unpack_skip_rows_ = param;
break;
case GL_UNPACK_SKIP_IMAGES:
unpack_skip_images_ = param;
break;
default:
WebGLRenderingContextBase::pixelStorei(pname, param);
return;
}
ContextGL()->PixelStorei(pname, param);
}
void WebGL2RenderingContextBase::readPixels(
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels) {
if (isContextLost())
return;
if (bound_pixel_pack_buffer_.Get()) {
SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
"PIXEL_PACK buffer should not be bound");
return;
}
ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), 0);
}
void WebGL2RenderingContextBase::readPixels(
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels,
GLuint offset) {
if (isContextLost())
return;
if (bound_pixel_pack_buffer_.Get()) {
SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
"PIXEL_PACK buffer should not be bound");
return;
}
ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), offset);
}
void WebGL2RenderingContextBase::readPixels(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
long long offset) {
if (isContextLost())
return;
// Due to WebGL's same-origin restrictions, it is not possible to
// taint the origin using the WebGL API.
DCHECK(canvas()->OriginClean());
if (!ValidateValueFitNonNegInt32("readPixels", "offset", offset))
return;
WebGLBuffer* buffer = bound_pixel_pack_buffer_.Get();
if (!buffer) {
SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
"no PIXEL_PACK buffer bound");
return;
}
const char* reason = "framebuffer incomplete";
WebGLFramebuffer* framebuffer = GetReadFramebufferBinding();
if (framebuffer && framebuffer->CheckDepthStencilStatus(&reason) !=
GL_FRAMEBUFFER_COMPLETE) {
SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
return;
}
long long size = buffer->GetSize() - offset;
// If size is negative, or size is not large enough to store pixels, those
// cases are handled by validateReadPixelsFuncParameters to generate
// INVALID_OPERATION.
if (!ValidateReadPixelsFuncParameters(width, height, format, type, nullptr,
size))
return;
ClearIfComposited();
{
ScopedDrawingBufferBinder binder(GetDrawingBuffer(), framebuffer);
ContextGL()->ReadPixels(x, y, width, height, format, type,
reinterpret_cast<void*>(offset));
}
}
void WebGL2RenderingContextBase::RenderbufferStorageHelper(
GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height,
const char* function_name) {
if (!samples) {
ContextGL()->RenderbufferStorage(target, internalformat, width, height);
} else {
GLint max_number_of_samples = 0;
ContextGL()->GetInternalformativ(target, internalformat, GL_SAMPLES, 1,
&max_number_of_samples);
if (samples > max_number_of_samples) {
SynthesizeGLError(GL_INVALID_OPERATION, function_name,
"samples out of range");
return;
}
ContextGL()->RenderbufferStorageMultisampleCHROMIUM(
target, samples, internalformat, width, height);
}
}
void WebGL2RenderingContextBase::RenderbufferStorageImpl(
GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height,
const char* function_name) {
switch (internalformat) {
case GL_R8UI:
case GL_R8I:
case GL_R16UI:
case GL_R16I:
case GL_R32UI:
case GL_R32I:
case GL_RG8UI:
case GL_RG8I:
case GL_RG16UI:
case GL_RG16I:
case GL_RG32UI:
case GL_RG32I:
case GL_RGBA8UI:
case GL_RGBA8I:
case GL_RGB10_A2UI:
case GL_RGBA16UI:
case GL_RGBA16I:
case GL_RGBA32UI:
case GL_RGBA32I:
if (samples > 0) {
SynthesizeGLError(GL_INVALID_OPERATION, function_name,
"for integer formats, samples > 0");
return;
}
FALLTHROUGH;
case GL_R8:
case GL_RG8:
case GL_RGB8:
case GL_RGB565:
case GL_RGBA8:
case GL_SRGB8_ALPHA8:
case GL_RGB5_A1:
case GL_RGBA4:
case GL_RGB10_A2:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH24_STENCIL8:
case GL_DEPTH32F_STENCIL8:
case GL_STENCIL_INDEX8:
RenderbufferStorageHelper(target, samples, internalformat, width, height,
function_name);
break;
case GL_DEPTH_STENCIL:
// To be WebGL 1 backward compatible.
if (samples > 0) {
SynthesizeGLError(GL_INVALID_ENUM, function_name,
"invalid internalformat");
return;
}
RenderbufferStorageHelper(target, 0, GL_DEPTH24_STENCIL8, width, height,
function_name);
break;
case GL_R16F:
case GL_RG16F:
case GL_RGBA16F:
case GL_R32F:
case GL_RG32F:
case GL_RGBA32F:
case GL_R11F_G11F_B10F:
if (!ExtensionEnabled(kEXTColorBufferFloatName)) {
SynthesizeGLError(GL_INVALID_ENUM, function_name,
"EXT_color_buffer_float not enabled");
return;
}
RenderbufferStorageHelper(target, samples, internalformat, width, height,
function_name);
break;
default:
SynthesizeGLError(GL_INVALID_ENUM, function_name,
"invalid internalformat");
return;
}
renderbuffer_binding_->SetInternalFormat(internalformat);
renderbuffer_binding_->SetSize(width, height);
}
void WebGL2RenderingContextBase::renderbufferStorageMultisample(
GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height) {
const char* function_name = "renderbufferStorageMultisample";
if (isContextLost())
return;
if (target != GL_RENDERBUFFER) {
SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
return;
}
if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
SynthesizeGLError(GL_INVALID_OPERATION, function_name,
"no bound renderbuffer");
return;
}
if (!ValidateSize("renderbufferStorage", width, height))
return;
if (samples < 0) {
SynthesizeGLError(GL_INVALID_VALUE, function_name, "samples < 0");
return;
}
RenderbufferStorageImpl(target, samples, internalformat, width, height,
function_name);
ApplyStencilTest();
}
void WebGL2RenderingContextBase::ResetUnpackParameters() {
WebGLRenderingContextBase::ResetUnpackParameters();
if (unpack_row_length_)
ContextGL()->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
if (unpack_image_height_)
ContextGL()->PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
if (unpack_skip_pixels_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
if (unpack_skip_rows_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
if (unpack_skip_images_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
}
void WebGL2RenderingContextBase::RestoreUnpackParameters() {
WebGLRenderingContextBase::RestoreUnpackParameters();
if (unpack_row_length_)
ContextGL()->PixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length_);
if (unpack_image_height_)
ContextGL()->PixelStorei(GL_UNPACK_IMAGE_HEIGHT, unpack_image_height_);
if (unpack_skip_pixels_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_PIXELS, unpack_skip_pixels_);
if (unpack_skip_rows_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_ROWS, unpack_skip_rows_);
if (unpack_skip_images_)
ContextGL()->PixelStorei(GL_UNPACK_SKIP_IMAGES, unpack_skip_images_);
}
/* Texture objects */
bool WebGL2RenderingContextBase::ValidateTexStorage(
const char* function_name,
GLenum target,
GLsizei levels,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
TexStorageType function_type) {
if (function_type == kTexStorageType2D) {
if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid 2D target");
return false;
}
} else {
if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY) {
SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid 3D target");
return false;
}
}
if (function_type == kTexStorageType3D && target != GL_TEXTURE_2D_ARRAY &&
compressed_texture_formats_etc2eac_.find(internalformat) !=
compressed_texture_formats_etc2eac_.end()) {
SynthesizeGLError(
GL_INVALID_OPERATION, function_name,
"target for ETC2/EAC internal formats must be TEXTURE_2D_ARRAY");
return false;
}
if (supported_internal_formats_storage_.find(internalformat) ==
supported_internal_formats_storage_.end() &&
(function_type == kTexStorageType2D &&
!compressed_texture_formats_.Contains(internalformat))) {
SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid internalformat");
return false;
}
if (width <= 0 || height <= 0 || depth <= 0) {
SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid dimensions");
return false;
}
if (levels <= 0) {
SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid levels");
return false;
}
if (target == GL_TEXTURE_3D) {
if (levels > log2(std::max(std::max(width, height), depth)) + 1) {
SynthesizeGLError(GL_INVALID_OPERATION, function_name, "to many levels");
return false;
}
} else {
if (levels > log2(std::max(width, height)) + 1) {
SynthesizeGLError(GL_INVALID_OPERATION, function_name, "to many levels");
return false;
}
}
return true;
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
GLintptr offset) {
if (isContextLost())
return;
if (!ValidateTexture2DBinding("texImage2D", target))
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
SynthesizeGLError(
GL_INVALID_OPERATION, "texImage2D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed while uploading from PBO");
return;
}
if (!ValidateTexFunc("texImage2D", kTexImage, kSourceUnpackBuffer, target,
level, internalformat, width, height, 1, border, format,
type, 0, 0, 0))
return;
if (!ValidateValueFitNonNegInt32("texImage2D", "offset", offset))
return;
ContextGL()->TexImage2D(
target, level, ConvertTexInternalFormat(internalformat, type), width,
height, border, format, type, reinterpret_cast<const void*>(offset));
}
void WebGL2RenderingContextBase::texSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLintptr offset) {
if (isContextLost())
return;
if (!ValidateTexture2DBinding("texSubImage2D", target))
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
SynthesizeGLError(
GL_INVALID_OPERATION, "texSubImage2D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed while uploading from PBO");
return;
}
if (!ValidateTexFunc("texSubImage2D", kTexSubImage, kSourceUnpackBuffer,
target, level, 0, width, height, 1, 0, format, type,
xoffset, yoffset, 0))
return;
if (!ValidateValueFitNonNegInt32("texSubImage2D", "offset", offset))
return;
ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height,
format, type,
reinterpret_cast<const void*>(offset));
}
void WebGL2RenderingContextBase::texImage2D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> data) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(target, level, internalformat, width,
height, border, format, type, data);
}
void WebGL2RenderingContextBase::texImage2D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> data,
GLuint src_offset) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperDOMArrayBufferView(
kTexImage2D, target, level, internalformat, width, height, 1, border,
format, type, 0, 0, 0, data.View(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
ImageData* pixels) {
DCHECK(pixels);
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageData(kTexImage2D, target, level, internalformat, 0, format,
type, 1, 0, 0, 0, pixels,
GetTextureSourceSubRectangle(width, height), 0);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
kTexImage2D, target, level, internalformat,
format, type, 0, 0, 0, image,
GetTextureSourceSubRectangle(width, height), 1,
unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLCanvasElement(
execution_context->GetSecurityOrigin(), kTexImage2D, target, level,
internalformat, format, type, 0, 0, 0, canvas,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLVideoElement(
execution_context->GetSecurityOrigin(), kTexImage2D, target, level,
internalformat, format, type, 0, 0, 0, video,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
ImageBitmap* bitmap,
ExceptionState& exception_state) {
DCHECK(bitmap);
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageBitmap(
kTexImage2D, target, level, internalformat, format, type, 0, 0, 0, bitmap,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
GLenum format,
GLenum type,
ImageData* image_data) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(target, level, internalformat, format,
type, image_data);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(execution_context, target, level,
internalformat, format, type, image,
exception_state);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(execution_context, target, level,
internalformat, format, type, canvas,
exception_state);
}
void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(execution_context, target, level,
internalformat, format, type, video,
exception_state);
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
GLenum format,
GLenum type,
ImageBitmap* image_bit_map,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texImage2D(target, level, internalformat, format,
type, image_bit_map, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texSubImage2D(target, level, xoffset, yoffset,
width, height, format, type, pixels);
}
void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels,
GLuint src_offset) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperDOMArrayBufferView(
kTexSubImage2D, target, level, 0, width, height, 1, 0, format, type,
xoffset, yoffset, 0, pixels.View(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
ImageData* pixels) {
DCHECK(pixels);
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageData(kTexSubImage2D, target, level, 0, 0, format, type, 1,
xoffset, yoffset, 0, pixels,
GetTextureSourceSubRectangle(width, height), 0);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLImageElement(
execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
format, type, xoffset, yoffset, 0, image,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLCanvasElement(
execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
format, type, xoffset, yoffset, 0, canvas,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLVideoElement(
execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
format, type, xoffset, yoffset, 0, video,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
ImageBitmap* bitmap,
ExceptionState& exception_state) {
DCHECK(bitmap);
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageBitmap(kTexSubImage2D, target, level, 0, format, type,
xoffset, yoffset, 0, bitmap,
GetTextureSourceSubRectangle(width, height), 1, 0,
exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLenum format,
GLenum type,
ImageData* pixels) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texSubImage2D(target, level, xoffset, yoffset,
format, type, pixels);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texSubImage2D(execution_context, target, level,
xoffset, yoffset, format, type,
image, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texSubImage2D(execution_context, target, level,
xoffset, yoffset, format, type,
canvas, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
WebGLRenderingContextBase::texSubImage2D(execution_context, target, level,
xoffset, yoffset, format, type,
video, exception_state);
}
void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLenum format,
GLenum type,
ImageBitmap* bitmap,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::texSubImage2D(
target, level, xoffset, yoffset, format, type, bitmap, exception_state);
}
void WebGL2RenderingContextBase::texStorage2D(GLenum target,
GLsizei levels,
GLenum internalformat,
GLsizei width,
GLsizei height) {
if (isContextLost() ||
!ValidateTexStorage("texStorage2D", target, levels, internalformat, width,
height, 1, kTexStorageType2D))
return;
ContextGL()->TexStorage2DEXT(target, levels, internalformat, width, height);
}
void WebGL2RenderingContextBase::texStorage3D(GLenum target,
GLsizei levels,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth) {
if (isContextLost() ||
!ValidateTexStorage("texStorage3D", target, levels, internalformat, width,
height, depth, kTexStorageType3D))
return;
ContextGL()->TexStorage3D(target, levels, internalformat, width, height,
depth);
}
void WebGL2RenderingContextBase::texImage3D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels) {
if ((unpack_flip_y_ || unpack_premultiply_alpha_) && pixels) {
SynthesizeGLError(
GL_INVALID_OPERATION, "texImage3D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed for uploading 3D textures");
return;
}
TexImageHelperDOMArrayBufferView(kTexImage3D, target, level, internalformat,
width, height, depth, border, format, type,
0, 0, 0, pixels.View(), kNullAllowed, 0);
}
void WebGL2RenderingContextBase::texImage3D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels,
GLuint src_offset) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
DCHECK(pixels);
SynthesizeGLError(
GL_INVALID_OPERATION, "texImage3D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed for uploading 3D textures");
return;
}
TexImageHelperDOMArrayBufferView(
kTexImage3D, target, level, internalformat, width, height, depth, border,
format, type, 0, 0, 0, pixels.View(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texImage3D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
GLintptr offset) {
if (isContextLost())
return;
if (!ValidateTexture3DBinding("texImage3D", target))
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
SynthesizeGLError(
GL_INVALID_OPERATION, "texImage3D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed for uploading 3D textures");
return;
}
if (!ValidateTexFunc("texImage3D", kTexImage, kSourceUnpackBuffer, target,
level, internalformat, width, height, depth, border,
format, type, 0, 0, 0))
return;
if (!ValidateValueFitNonNegInt32("texImage3D", "offset", offset))
return;
ContextGL()->TexImage3D(target, level,
ConvertTexInternalFormat(internalformat, type), width,
height, depth, border, format, type,
reinterpret_cast<const void*>(offset));
}
void WebGL2RenderingContextBase::texImage3D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
ImageData* pixels) {
DCHECK(pixels);
IntRect source_image_rect;
source_image_rect.SetLocation(
IntPoint(unpack_skip_pixels_, unpack_skip_rows_));
source_image_rect.SetSize(IntSize(width, height));
TexImageHelperImageData(kTexImage3D, target, level, internalformat, 0, format,
type, depth, 0, 0, 0, pixels, source_image_rect,
unpack_image_height_);
}
void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
kTexImage3D, target, level, internalformat,
format, type, 0, 0, 0, image,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLCanvasElement(execution_context->GetSecurityOrigin(),
kTexImage3D, target, level, internalformat,
format, type, 0, 0, 0, canvas,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
kTexImage3D, target, level, internalformat,
format, type, 0, 0, 0, video,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texImage3D(GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
ImageBitmap* bitmap,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageBitmap(kTexImage3D, target, level, internalformat, format,
type, 0, 0, 0, bitmap,
GetTextureSourceSubRectangle(width, height), depth,
unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texSubImage3D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels,
GLuint src_offset) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
DCHECK(pixels);
SynthesizeGLError(
GL_INVALID_OPERATION, "texSubImage3D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed for uploading 3D textures");
return;
}
TexImageHelperDOMArrayBufferView(
kTexSubImage3D, target, level, 0, width, height, depth, 0, format, type,
xoffset, yoffset, zoffset, pixels.View(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
GLintptr offset) {
if (isContextLost())
return;
if (!ValidateTexture3DBinding("texSubImage3D", target))
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
if (unpack_flip_y_ || unpack_premultiply_alpha_) {
SynthesizeGLError(
GL_INVALID_OPERATION, "texSubImage3D",
"FLIP_Y or PREMULTIPLY_ALPHA isn't allowed for uploading 3D textures");
return;
}
if (!ValidateTexFunc("texSubImage3D", kTexSubImage, kSourceUnpackBuffer,
target, level, 0, width, height, depth, 0, format, type,
xoffset, yoffset, zoffset))
return;
if (!ValidateValueFitNonNegInt32("texSubImage3D", "offset", offset))
return;
ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
height, depth, format, type,
reinterpret_cast<const void*>(offset));
}
void WebGL2RenderingContextBase::texSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
ImageData* pixels) {
DCHECK(pixels);
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageData(kTexSubImage3D, target, level, 0, 0, format, type,
depth, xoffset, yoffset, zoffset, pixels,
GetTextureSourceSubRectangle(width, height),
unpack_image_height_);
}
void WebGL2RenderingContextBase::texSubImage3D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
HTMLImageElement* image,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
kTexSubImage3D, target, level, 0, format, type,
xoffset, yoffset, zoffset, image,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texSubImage3D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
HTMLCanvasElement* canvas,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLCanvasElement(execution_context->GetSecurityOrigin(),
kTexSubImage3D, target, level, 0, format,
type, xoffset, yoffset, zoffset, canvas,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texSubImage3D(
ExecutionContext* execution_context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
HTMLVideoElement* video,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
kTexSubImage3D, target, level, 0, format, type,
xoffset, yoffset, zoffset, video,
GetTextureSourceSubRectangle(width, height),
depth, unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::texSubImage3D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
ImageBitmap* bitmap,
ExceptionState& exception_state) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
TexImageHelperImageBitmap(kTexSubImage3D, target, level, 0, format, type,
xoffset, yoffset, zoffset, bitmap,
GetTextureSourceSubRectangle(width, height), depth,
unpack_image_height_, exception_state);
}
void WebGL2RenderingContextBase::copyTexSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height) {
if (isContextLost())
return;
if (!ValidateTexture3DBinding("copyTexSubImage3D", target))
return;
WebGLFramebuffer* read_framebuffer_binding = nullptr;
if (!ValidateReadBufferAndGetInfo("copyTexSubImage3D",
read_framebuffer_binding))
return;
ClearIfComposited();
ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
read_framebuffer_binding);
ContextGL()->CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y,
width, height);
}
void WebGL2RenderingContextBase::compressedTexImage2D(
GLenum target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLint border,
MaybeShared<DOMArrayBufferView> data) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::compressedTexImage2D(target, level, internalformat,
width, height, border, data);
}
void WebGL2RenderingContextBase::compressedTexImage2D(
GLenum target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLint border,
MaybeShared<DOMArrayBufferView> data,
GLuint src_offset,
GLuint src_length_override) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (!ValidateTexture2DBinding("compressedTexImage2D", target))
return;
if (!ValidateCompressedTexFormat("compressedTexImage2D", internalformat))
return;
if (src_offset > data.View()->byteLength()) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D",
"srcOffset is out of range");
return;
}
if (src_length_override == 0) {
src_length_override = data.View()->byteLength() - src_offset;
} else if (src_length_override > data.View()->byteLength() - src_offset) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D",
"srcLengthOverride is out of range");
return;
}
ContextGL()->CompressedTexImage2D(
target, level, internalformat, width, height, border, src_length_override,
static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
src_offset);
}
void WebGL2RenderingContextBase::compressedTexImage2D(GLenum target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLsizei image_size,
GLintptr offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexImage2D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
ContextGL()->CompressedTexImage2D(target, level, internalformat, width,
height, border, image_size,
reinterpret_cast<uint8_t*>(offset));
}
void WebGL2RenderingContextBase::compressedTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
MaybeShared<DOMArrayBufferView> data) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
WebGLRenderingContextBase::compressedTexSubImage2D(
target, level, xoffset, yoffset, width, height, format, data);
}
void WebGL2RenderingContextBase::compressedTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
MaybeShared<DOMArrayBufferView> data,
GLuint src_offset,
GLuint src_length_override) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (!ValidateTexture2DBinding("compressedTexSubImage2D", target))
return;
if (!ValidateCompressedTexFormat("compressedTexSubImage2D", format))
return;
if (src_offset > data.View()->byteLength()) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexSubImage2D",
"srcOffset is out of range");
return;
}
if (src_length_override == 0) {
src_length_override = data.View()->byteLength() - src_offset;
} else if (src_length_override > data.View()->byteLength() - src_offset) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D",
"srcLengthOverride is out of range");
return;
}
ContextGL()->CompressedTexSubImage2D(
target, level, xoffset, yoffset, width, height, format,
src_length_override,
static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
src_offset);
}
void WebGL2RenderingContextBase::compressedTexSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLsizei image_size,
GLintptr offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
ContextGL()->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
height, format, image_size,
reinterpret_cast<uint8_t*>(offset));
}
void WebGL2RenderingContextBase::compressedTexImage3D(
GLenum target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
MaybeShared<DOMArrayBufferView> data,
GLuint src_offset,
GLuint src_length_override) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (!ValidateTexture3DBinding("compressedTexImage3D", target))
return;
if (!ValidateCompressedTexFormat("compressedTexImage3D", internalformat))
return;
if (src_offset > data.View()->byteLength()) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexImage3D",
"srcOffset is out of range");
return;
}
if (src_length_override == 0) {
src_length_override = data.View()->byteLength() - src_offset;
} else if (src_length_override > data.View()->byteLength() - src_offset) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexImage3D",
"srcLengthOverride is out of range");
return;
}
ContextGL()->CompressedTexImage3D(
target, level, internalformat, width, height, depth, border,
src_length_override,
static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
src_offset);
}
void WebGL2RenderingContextBase::compressedTexImage3D(GLenum target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLsizei image_size,
GLintptr offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexImage3D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
ContextGL()->CompressedTexImage3D(target, level, internalformat, width,
height, depth, border, image_size,
reinterpret_cast<uint8_t*>(offset));
}
void WebGL2RenderingContextBase::compressedTexSubImage3D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
MaybeShared<DOMArrayBufferView> data,
GLuint src_offset,
GLuint src_length_override) {
if (isContextLost())
return;
if (bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage3D",
"a buffer is bound to PIXEL_UNPACK_BUFFER");
return;
}
if (!ValidateTexture3DBinding("compressedTexSubImage3D", target))
return;
if (!ValidateCompressedTexFormat("compressedTexSubImage3D", format))
return;
if (src_offset > data.View()->byteLength()) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexSubImage3D",
"srcOffset is out of range");
return;
}
if (src_length_override == 0) {
src_length_override = data.View()->byteLength() - src_offset;
} else if (src_length_override > data.View()->byteLength() - src_offset) {
SynthesizeGLError(GL_INVALID_VALUE, "compressedTexSubImage3D",
"srcLengthOverride is out of range");
return;
}
ContextGL()->CompressedTexSubImage3D(
target, level, xoffset, yoffset, zoffset, width, height, depth, format,
src_length_override,
static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
src_offset);
}
void WebGL2RenderingContextBase::compressedTexSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLsizei image_size,
GLintptr offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
SynthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage3D",
"no bound PIXEL_UNPACK_BUFFER");
return;
}
ContextGL()->CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset,
width, height, depth, format, image_size,
reinterpret_cast<uint8_t*>(offset));
}
GLint WebGL2RenderingContextBase::getFragDataLocation(WebGLProgram* program,
const String& name) {
if (isContextLost() || !ValidateWebGLObject("getFragDataLocation", program))
return -1;
return ContextGL()->GetFragDataLocation(ObjectOrZero(program),
name.Utf8().data());
}
void WebGL2RenderingContextBase::uniform1ui(
const WebGLUniformLocation* location,
GLuint v0) {
if (isContextLost() || !location)
return;
if (location->Program() != current_program_) {
SynthesizeGLError(GL_INVALID_OPERATION, "uniform1ui",
"location not for current program");
return;
}
ContextGL()->Uniform1ui(location->Location(), v0);
}
void WebGL2RenderingContextBase::uniform2ui(
const WebGLUniformLocation* location,
GLuint v0,
GLuint v1) {
if (isContextLost() || !location)
return;
if (location->Program() != current_program_) {
SynthesizeGLError(GL_INVALID_OPERATION, "uniform2ui",
"location not for current program");
return;
}
ContextGL()->Uniform2ui(location->Location(), v0, v1);
}
void WebGL2RenderingContextBase::uniform3ui(
const WebGLUniformLocation* location,
GLuint v0,
GLuint v1,
GLuint v2) {
if (isContextLost() || !location)
return;
if (location->Program() != current_program_) {
SynthesizeGLError(GL_INVALID_OPERATION, "uniform3ui",
"location not for current program");
return;
}
ContextGL()->Uniform3ui(location->Location(), v0, v1, v2);
}
void WebGL2RenderingContextBase::uniform4ui(
const WebGLUniformLocation* location,
GLuint v0,
GLuint v1,
GLuint v2,
GLuint v3) {
if (isContextLost() || !location)
return;
if (location->Program() != current_program_) {
SynthesizeGLError(GL_INVALID_OPERATION, "uniform4ui",
"location not for current program");
return;
}
ContextGL()->Uniform4ui(location->Location(), v0, v1, v2, v3);
}
void WebGL2RenderingContextBase::uniform1fv(
const WebGLUniformLocation* location,
const FlexibleFloat32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Float32Array>("uniform1fv", location, v,
1, src_offset, src_length))
return;
ContextGL()->Uniform1fv(location->Location(),
src_length ? src_length : (v.length() - src_offset),
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform1fv(
const WebGLUniformLocation* location,
Vector<GLfloat>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters("uniform1fv", location, v.data(), v.size(), 1,
src_offset, src_length))
return;
ContextGL()->Uniform1fv(location->Location(),
src_length ? src_length : (v.size() - src_offset),
v.data() + src_offset);
}
void WebGL2RenderingContextBase::uniform2fv(
const WebGLUniformLocation* location,
const FlexibleFloat32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Float32Array>("uniform2fv", location, v,
2, src_offset, src_length))
return;
ContextGL()->Uniform2fv(
location->Location(),
(src_length ? src_length : (v.length() - src_offset)) >> 1,
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform2fv(
const WebGLUniformLocation* location,
Vector<GLfloat>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters("uniform2fv", location, v.data(), v.size(), 2,
src_offset, src_length))
return;
ContextGL()->Uniform2fv(
location->Location(),
(src_length ? src_length : (v.size() - src_offset)) >> 1,
v.data() + src_offset);
}
void WebGL2RenderingContextBase::uniform3fv(
const WebGLUniformLocation* location,
const FlexibleFloat32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Float32Array>("uniform3fv", location, v,
3, src_offset, src_length))
return;
ContextGL()->Uniform3fv(
location->Location(),
(src_length ? src_length : (v.length() - src_offset)) / 3,
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform3fv(
const WebGLUniformLocation* location,
Vector<GLfloat>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters("uniform3fv", location, v.data(), v.size(), 3,
src_offset, src_length))
return;
ContextGL()->Uniform3fv(
location->Location(),
(src_length ? src_length : (v.size() - src_offset)) / 3,
v.data() + src_offset);
}
void WebGL2RenderingContextBase::uniform4fv(
const WebGLUniformLocation* location,
const FlexibleFloat32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Float32Array>("uniform4fv", location, v,
4, src_offset, src_length))
return;
ContextGL()->Uniform4fv(
location->Location(),
(src_length ? src_length : (v.length() - src_offset)) >> 2,
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform4fv(
const WebGLUniformLocation* location,
Vector<GLfloat>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters("uniform4fv", location, v.data(), v.size(), 4,
src_offset, src_length))
return;
ContextGL()->Uniform4fv(
location->Location(),
(src_length ? src_length : (v.size() - src_offset)) >> 2,
v.data() + src_offset);
}
void WebGL2RenderingContextBase::uniform1iv(
const WebGLUniformLocation* location,
const FlexibleInt32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Int32Array>("uniform1iv", location, v, 1,
src_offset, src_length))
return;
ContextGL()->Uniform1iv(location->Location(),
src_length ? src_length : (v.length() - src_offset),
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform1iv(
const WebGLUniformLocation* location,
Vector<GLint>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters("uniform1iv", location, v.data(), v.size(), 1,
src_offset, src_length))
return;
ContextGL()->Uniform1iv(location->Location(),
src_length ? src_length : (v.size() - src_offset),
v.data() + src_offset);
}
void WebGL2RenderingContextBase::uniform2iv(
const WebGLUniformLocation* location,
const FlexibleInt32ArrayView& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformParameters<WTF::Int32Array>("uniform2iv", location, v, 2,
src_offset, src_length))
return;
ContextGL()->Uniform2iv(
location->Location(),
(src_length ? src_length : (v.length() - src_offset)) >> 1,
v.DataMaybeOnStack() + src_offset);
}
void WebGL2RenderingContextBase::uniform2iv(
const WebGLUniformLocation* location,
Vector<GLint>& v,
GLuint src_offset,
GLuint src_length) {
if (isContextLost()