blob: b87af68ca0f75669382671aa4e27c26755e7321c [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h"
#include <algorithm>
#include <memory>
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
#include "third_party/blink/renderer/modules/webgl/webgl_program.h"
#include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
WebGL2ComputeRenderingContextBase::WebGL2ComputeRenderingContextBase(
CanvasRenderingContextHost* host,
std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
bool using_gpu_compositing,
const CanvasContextCreationAttributesCore& requested_attributes)
: WebGL2RenderingContextBase(host,
std::move(context_provider),
using_gpu_compositing,
requested_attributes,
Platform::kWebGL2ComputeContextType) {}
void WebGL2ComputeRenderingContextBase::DestroyContext() {
WebGL2RenderingContextBase::DestroyContext();
}
void WebGL2ComputeRenderingContextBase::InitializeNewContext() {
DCHECK(!isContextLost());
WebGL2RenderingContextBase::InitializeNewContext();
}
void WebGL2ComputeRenderingContextBase::dispatchCompute(GLuint numGroupsX,
GLuint numGroupsY,
GLuint numGroupsZ) {
ContextGL()->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
}
ScriptValue WebGL2ComputeRenderingContextBase::getProgramInterfaceParameter(
ScriptState* script_state,
WebGLProgram* program,
GLenum program_interface,
GLenum pname) {
if (!ValidateWebGLProgramOrShader("getProgramInterfaceParameter", program))
return ScriptValue::CreateNull(script_state);
switch (pname) {
case GL_ACTIVE_RESOURCES:
case GL_MAX_NAME_LENGTH:
case GL_MAX_NUM_ACTIVE_VARIABLES: {
GLint value = 0;
ContextGL()->GetProgramInterfaceiv(
ObjectOrZero(program), program_interface, pname, &value);
return WebGLAny(script_state, value);
}
default:
SynthesizeGLError(GL_INVALID_ENUM, "getProgramInterfaceParameter",
"invalid parameter name");
return ScriptValue::CreateNull(script_state);
}
}
GLuint WebGL2ComputeRenderingContextBase::getProgramResourceIndex(
WebGLProgram* program,
GLenum program_interface,
const String& name) {
if (!ValidateWebGLProgramOrShader("getProgramResourceIndex", program))
return 0;
return ContextGL()->GetProgramResourceIndex(
ObjectOrZero(program), program_interface, name.Utf8().data());
}
String WebGL2ComputeRenderingContextBase::getProgramResourceName(
WebGLProgram* program,
GLenum program_interface,
GLuint index) {
if (!ValidateWebGLProgramOrShader("getProgramResourceName", program))
return String();
GLint max_name_length = -1;
ContextGL()->GetProgramInterfaceiv(ObjectOrZero(program), program_interface,
GL_MAX_NAME_LENGTH, &max_name_length);
if (max_name_length <= 0) {
SynthesizeGLError(GL_INVALID_VALUE, "getProgramResourceName",
"invalid program interface");
return String();
}
auto name = std::make_unique<GLchar[]>(max_name_length);
GLsizei length = 0;
ContextGL()->GetProgramResourceName(ObjectOrZero(program), program_interface,
index, max_name_length, &length,
name.get());
if (length <= 0)
return String();
return String(name.get(), static_cast<uint32_t>(length));
}
base::Optional<Vector<ScriptValue>>
WebGL2ComputeRenderingContextBase::getProgramResource(
ScriptState* script_state,
WebGLProgram* program,
GLenum program_interface,
GLuint index,
const Vector<GLenum>& props) {
if (!ValidateWebGLProgramOrShader("getProgramResource", program))
return base::nullopt;
Vector<GLenum> auxiliary_props;
Vector<GLint> auxiliary_params;
Vector<GLenum> extended_props;
Vector<GLint> extended_params;
for (GLenum prop : props) {
switch (prop) {
// Handle props with fixed-length return values.
case GL_ARRAY_SIZE:
case GL_ARRAY_STRIDE:
case GL_ATOMIC_COUNTER_BUFFER_INDEX:
case GL_BLOCK_INDEX:
case GL_BUFFER_BINDING:
case GL_BUFFER_DATA_SIZE:
case GL_IS_ROW_MAJOR:
case GL_LOCATION:
case GL_MATRIX_STRIDE:
case GL_NAME_LENGTH:
case GL_NUM_ACTIVE_VARIABLES:
case GL_OFFSET:
case GL_REFERENCED_BY_COMPUTE_SHADER:
case GL_REFERENCED_BY_FRAGMENT_SHADER:
case GL_REFERENCED_BY_VERTEX_SHADER:
case GL_TOP_LEVEL_ARRAY_SIZE:
case GL_TOP_LEVEL_ARRAY_STRIDE:
case GL_TYPE:
extended_props.push_back(prop);
extended_params.push_back(0);
break;
// Handle props with variable-length return values. For these props, their
// lengths will be queried first by constructing |auxiliary_props| as the
// following, and |extended_params| will be adequately sized for the whole
// result after that.
case GL_ACTIVE_VARIABLES:
auxiliary_props.push_back(GL_NUM_ACTIVE_VARIABLES);
auxiliary_params.push_back(-1);
extended_props.push_back(GL_ACTIVE_VARIABLES);
break;
default:
SynthesizeGLError(GL_INVALID_ENUM, "getProgramResource",
"invalid program resource property");
return base::nullopt;
}
}
extended_props.PrependVector(auxiliary_props);
extended_params.PrependVector(auxiliary_params);
if (auxiliary_props.size()) {
ContextGL()->GetProgramResourceiv(ObjectOrZero(program), program_interface,
index, auxiliary_props.size(),
auxiliary_props.data(),
auxiliary_params.size(), nullptr,
auxiliary_params.data());
for (GLint n : auxiliary_params) {
extended_params.resize(extended_params.size() + std::max(n, 0));
}
}
GLsizei length = 0;
ContextGL()->GetProgramResourceiv(ObjectOrZero(program), program_interface,
index, extended_props.size(),
extended_props.data(),
extended_params.size(), &length,
extended_params.data());
if (length <= 0) {
return base::nullopt;
}
for (wtf_size_t i = 0; i < auxiliary_params.size(); ++i) {
// The returned lengths really should not differ from the previous ones.
CHECK_EQ(extended_params[i], auxiliary_params[i]);
}
// Interpret the returned values and construct the result array. The type of
// each array element is the natural type for the requested property.
Vector<ScriptValue> result;
wtf_size_t auxiliary_param_index = 0;
wtf_size_t extended_param_index = auxiliary_params.size();
for (GLenum prop : props) {
switch (prop) {
case GL_IS_ROW_MAJOR:
case GL_REFERENCED_BY_COMPUTE_SHADER:
case GL_REFERENCED_BY_FRAGMENT_SHADER:
case GL_REFERENCED_BY_VERTEX_SHADER: {
bool value = extended_params[extended_param_index];
result.push_back(WebGLAny(script_state, value));
++extended_param_index;
break;
}
case GL_ARRAY_STRIDE:
case GL_ATOMIC_COUNTER_BUFFER_INDEX:
case GL_BLOCK_INDEX:
case GL_MATRIX_STRIDE:
case GL_OFFSET: {
int value = extended_params[extended_param_index];
result.push_back(WebGLAny(script_state, value));
++extended_param_index;
break;
}
case GL_LOCATION: {
int value = extended_params[extended_param_index];
result.push_back(
WrapLocation(script_state, value, program, program_interface));
++extended_param_index;
break;
}
case GL_ARRAY_SIZE:
case GL_BUFFER_BINDING:
case GL_BUFFER_DATA_SIZE:
case GL_NAME_LENGTH:
case GL_NUM_ACTIVE_VARIABLES:
case GL_TOP_LEVEL_ARRAY_SIZE:
case GL_TOP_LEVEL_ARRAY_STRIDE: {
unsigned value = extended_params[extended_param_index];
result.push_back(WebGLAny(script_state, value));
++extended_param_index;
break;
}
case GL_TYPE: {
GLenum value = extended_params[extended_param_index];
result.push_back(WebGLAny(script_state, value));
++extended_param_index;
break;
}
case GL_ACTIVE_VARIABLES: {
DOMUint32Array* value = DOMUint32Array::Create(
reinterpret_cast<unsigned*>(&extended_params[extended_param_index]),
auxiliary_params[auxiliary_param_index]);
result.push_back(WebGLAny(script_state, value));
extended_param_index += auxiliary_params[auxiliary_param_index];
++auxiliary_param_index;
break;
}
default:
NOTREACHED();
}
}
return result;
}
ScriptValue WebGL2ComputeRenderingContextBase::getProgramResourceLocation(
ScriptState* script_state,
WebGLProgram* program,
GLenum program_interface,
const String& name) {
if (!ValidateWebGLProgramOrShader("getProgramResourceLocation", program))
return WrapLocation(script_state, -1, program, program_interface);
GLint location = ContextGL()->GetProgramResourceLocation(
ObjectOrZero(program), program_interface, name.Utf8().data());
return WrapLocation(script_state, location, program, program_interface);
}
void WebGL2ComputeRenderingContextBase::bindImageTexture(GLuint unit,
WebGLTexture* texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format) {
ContextGL()->BindImageTexture(unit, ObjectOrZero(texture), level, layered,
layer, access, format);
}
void WebGL2ComputeRenderingContextBase::memoryBarrier(GLbitfield barriers) {
ContextGL()->MemoryBarrierEXT(barriers);
}
void WebGL2ComputeRenderingContextBase::memoryBarrierByRegion(
GLbitfield barriers) {
ContextGL()->MemoryBarrierByRegion(barriers);
}
ScriptValue WebGL2ComputeRenderingContextBase::getParameter(
ScriptState* script_state,
GLenum pname) {
if (isContextLost())
return ScriptValue::CreateNull(script_state);
switch (pname) {
case GL_SHADING_LANGUAGE_VERSION: {
return WebGLAny(
script_state,
"WebGL GLSL ES 3.10 (" +
String(ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION)) +
")");
}
case GL_VERSION: {
return WebGLAny(script_state,
"WebGL 2.0 Compute (" +
String(ContextGL()->GetString(GL_VERSION)) + ")");
}
case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE:
case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_COMBINED_ATOMIC_COUNTERS:
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE:
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS:
case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS:
case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_VERTEX_ATOMIC_COUNTERS:
case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS:
return GetIntParameter(script_state, pname);
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
return GetInt64Parameter(script_state, pname);
default:
return WebGL2RenderingContextBase::getParameter(script_state, pname);
}
}
void WebGL2ComputeRenderingContextBase::Trace(blink::Visitor* visitor) {
WebGL2RenderingContextBase::Trace(visitor);
}
ScriptValue WebGL2ComputeRenderingContextBase::WrapLocation(
ScriptState* script_state,
GLint location,
WebGLProgram* program,
GLenum program_interface) {
switch (program_interface) {
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT: {
return WebGLAny(script_state, location);
}
case GL_UNIFORM: {
if (location == -1)
return ScriptValue::CreateNull(script_state);
DCHECK_GE(location, 0);
WebGLUniformLocation* uniform_location =
WebGLUniformLocation::Create(program, location);
return ScriptValue(script_state, ToV8(uniform_location, script_state));
}
default: {
return WebGLAny(script_state, location);
}
}
}
} // namespace blink