mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
This makes the WebGL2 implementation file inherit from the WebGL1 implementation file. This is actually closer to what the IDL files describe and allows us to not have to maintain two copies of the same functions.
2240 lines
75 KiB
C++
2240 lines
75 KiB
C++
/*
|
|
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
* Copyright (c) 2024-2025, Luke Wilde <luke@ladybird.org>
|
|
* Copyright (c) 2025, Undefine <undefine@undefine.pl>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#define GL_GLEXT_PROTOTYPES 1
|
|
|
|
#include <GLES3/gl3.h>
|
|
extern "C" {
|
|
#include <GLES2/gl2ext.h>
|
|
#include <GLES2/gl2ext_angle.h>
|
|
}
|
|
|
|
#include <LibJS/Runtime/ArrayBuffer.h>
|
|
#include <LibJS/Runtime/DataView.h>
|
|
#include <LibJS/Runtime/TypedArray.h>
|
|
#include <LibWeb/WebGL/OpenGLContext.h>
|
|
#include <LibWeb/WebGL/WebGLActiveInfo.h>
|
|
#include <LibWeb/WebGL/WebGLBuffer.h>
|
|
#include <LibWeb/WebGL/WebGLFramebuffer.h>
|
|
#include <LibWeb/WebGL/WebGLProgram.h>
|
|
#include <LibWeb/WebGL/WebGLRenderbuffer.h>
|
|
#include <LibWeb/WebGL/WebGLRenderingContextImpl.h>
|
|
#include <LibWeb/WebGL/WebGLSampler.h>
|
|
#include <LibWeb/WebGL/WebGLShader.h>
|
|
#include <LibWeb/WebGL/WebGLShaderPrecisionFormat.h>
|
|
#include <LibWeb/WebGL/WebGLSync.h>
|
|
#include <LibWeb/WebGL/WebGLTexture.h>
|
|
#include <LibWeb/WebGL/WebGLTransformFeedback.h>
|
|
#include <LibWeb/WebGL/WebGLUniformLocation.h>
|
|
#include <LibWeb/WebGL/WebGLVertexArrayObject.h>
|
|
#include <LibWeb/WebIDL/Buffers.h>
|
|
|
|
namespace Web::WebGL {
|
|
|
|
WebGLRenderingContextImpl::WebGLRenderingContextImpl(JS::Realm& realm, NonnullOwnPtr<OpenGLContext> context)
|
|
: m_realm(realm)
|
|
, m_context(move(context))
|
|
{
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::active_texture(WebIDL::UnsignedLong texture)
|
|
{
|
|
m_context->make_current();
|
|
glActiveTexture(texture);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::attach_shader(GC::Root<WebGLProgram> program, GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLuint shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
if (program->attached_vertex_shader() == shader || program->attached_fragment_shader() == shader) {
|
|
dbgln("WebGL: Shader is already attached to program");
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
|
|
if (shader->type() == GL_VERTEX_SHADER && program->attached_vertex_shader()) {
|
|
dbgln("WebGL: Not attaching vertex shader to program as it already has a vertex shader attached");
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
|
|
if (shader->type() == GL_FRAGMENT_SHADER && program->attached_fragment_shader()) {
|
|
dbgln("WebGL: Not attaching fragment shader to program as it already has a fragment shader attached");
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
|
|
glAttachShader(program_handle, shader_handle);
|
|
|
|
switch (shader->type()) {
|
|
case GL_VERTEX_SHADER:
|
|
program->set_attached_vertex_shader(shader.ptr());
|
|
break;
|
|
case GL_FRAGMENT_SHADER:
|
|
program->set_attached_fragment_shader(shader.ptr());
|
|
break;
|
|
default:
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::bind_attrib_location(GC::Root<WebGLProgram> program, WebIDL::UnsignedLong index, String name)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
auto name_null_terminated = null_terminated_string(name);
|
|
glBindAttribLocation(program_handle, index, name_null_terminated.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::bind_buffer(WebIDL::UnsignedLong target, GC::Root<WebGLBuffer> buffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint buffer_handle = 0;
|
|
if (buffer) {
|
|
auto handle_or_error = buffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
buffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
switch (target) {
|
|
case GL_ARRAY_BUFFER:
|
|
m_array_buffer_binding = buffer;
|
|
break;
|
|
case GL_COPY_READ_BUFFER:
|
|
m_copy_read_buffer_binding = buffer;
|
|
break;
|
|
case GL_COPY_WRITE_BUFFER:
|
|
m_copy_write_buffer_binding = buffer;
|
|
break;
|
|
case GL_ELEMENT_ARRAY_BUFFER:
|
|
m_element_array_buffer_binding = buffer;
|
|
break;
|
|
case GL_PIXEL_PACK_BUFFER:
|
|
m_pixel_pack_buffer_binding = buffer;
|
|
break;
|
|
case GL_PIXEL_UNPACK_BUFFER:
|
|
m_pixel_unpack_buffer_binding = buffer;
|
|
break;
|
|
case GL_TRANSFORM_FEEDBACK_BUFFER:
|
|
m_transform_feedback_buffer_binding = buffer;
|
|
break;
|
|
case GL_UNIFORM_BUFFER:
|
|
m_uniform_buffer_binding = buffer;
|
|
break;
|
|
default:
|
|
dbgln("Unknown WebGL buffer object binding target for storing current binding: 0x{:04x}", target);
|
|
set_error(GL_INVALID_ENUM);
|
|
return;
|
|
}
|
|
} else {
|
|
switch (target) {
|
|
case GL_ELEMENT_ARRAY_BUFFER:
|
|
m_element_array_buffer_binding = buffer;
|
|
break;
|
|
case GL_ARRAY_BUFFER:
|
|
m_array_buffer_binding = buffer;
|
|
break;
|
|
default:
|
|
dbgln("Unknown WebGL buffer object binding target for storing current binding: 0x{:04x}", target);
|
|
set_error(GL_INVALID_ENUM);
|
|
return;
|
|
}
|
|
}
|
|
|
|
glBindBuffer(target, buffer_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::bind_framebuffer(WebIDL::UnsignedLong target, GC::Root<WebGLFramebuffer> framebuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint framebuffer_handle = 0;
|
|
if (framebuffer) {
|
|
auto handle_or_error = framebuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
framebuffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glBindFramebuffer(target, framebuffer ? framebuffer_handle : m_context->default_framebuffer());
|
|
m_framebuffer_binding = framebuffer;
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::bind_renderbuffer(WebIDL::UnsignedLong target, GC::Root<WebGLRenderbuffer> renderbuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint renderbuffer_handle = 0;
|
|
if (renderbuffer) {
|
|
auto handle_or_error = renderbuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
renderbuffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glBindRenderbuffer(target, renderbuffer ? renderbuffer_handle : m_context->default_renderbuffer());
|
|
m_renderbuffer_binding = renderbuffer;
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::bind_texture(WebIDL::UnsignedLong target, GC::Root<WebGLTexture> texture)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint texture_handle = 0;
|
|
if (texture) {
|
|
auto handle_or_error = texture->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
texture_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
switch (target) {
|
|
case GL_TEXTURE_2D:
|
|
m_texture_binding_2d = texture;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP:
|
|
m_texture_binding_cube_map = texture;
|
|
break;
|
|
|
|
case GL_TEXTURE_2D_ARRAY:
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
m_texture_binding_2d_array = texture;
|
|
break;
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return;
|
|
case GL_TEXTURE_3D:
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
m_texture_binding_3d = texture;
|
|
break;
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return;
|
|
|
|
default:
|
|
dbgln("Unknown WebGL texture target for storing current binding: 0x{:04x}", target);
|
|
set_error(GL_INVALID_ENUM);
|
|
return;
|
|
}
|
|
glBindTexture(target, texture_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::blend_color(float red, float green, float blue, float alpha)
|
|
{
|
|
m_context->make_current();
|
|
glBlendColor(red, green, blue, alpha);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::blend_equation(WebIDL::UnsignedLong mode)
|
|
{
|
|
m_context->make_current();
|
|
glBlendEquation(mode);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::blend_equation_separate(WebIDL::UnsignedLong mode_rgb, WebIDL::UnsignedLong mode_alpha)
|
|
{
|
|
m_context->make_current();
|
|
glBlendEquationSeparate(mode_rgb, mode_alpha);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::blend_func(WebIDL::UnsignedLong sfactor, WebIDL::UnsignedLong dfactor)
|
|
{
|
|
m_context->make_current();
|
|
glBlendFunc(sfactor, dfactor);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::blend_func_separate(WebIDL::UnsignedLong src_rgb, WebIDL::UnsignedLong dst_rgb, WebIDL::UnsignedLong src_alpha, WebIDL::UnsignedLong dst_alpha)
|
|
{
|
|
m_context->make_current();
|
|
glBlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha);
|
|
}
|
|
|
|
WebIDL::UnsignedLong WebGLRenderingContextImpl::check_framebuffer_status(WebIDL::UnsignedLong target)
|
|
{
|
|
m_context->make_current();
|
|
return glCheckFramebufferStatus(target);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::clear(WebIDL::UnsignedLong mask)
|
|
{
|
|
m_context->make_current();
|
|
m_context->notify_content_will_change();
|
|
needs_to_present();
|
|
glClear(mask);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::clear_color(float red, float green, float blue, float alpha)
|
|
{
|
|
m_context->make_current();
|
|
glClearColor(red, green, blue, alpha);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::clear_depth(float depth)
|
|
{
|
|
m_context->make_current();
|
|
glClearDepthf(depth);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::clear_stencil(WebIDL::Long s)
|
|
{
|
|
m_context->make_current();
|
|
glClearStencil(s);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::color_mask(bool red, bool green, bool blue, bool alpha)
|
|
{
|
|
m_context->make_current();
|
|
glColorMask(red, green, blue, alpha);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::compile_shader(GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
glCompileShader(shader_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::copy_tex_image2d(WebIDL::UnsignedLong target, WebIDL::Long level, WebIDL::UnsignedLong internalformat, WebIDL::Long x, WebIDL::Long y, WebIDL::Long width, WebIDL::Long height, WebIDL::Long border)
|
|
{
|
|
m_context->make_current();
|
|
glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::copy_tex_sub_image2d(WebIDL::UnsignedLong target, WebIDL::Long level, WebIDL::Long xoffset, WebIDL::Long yoffset, WebIDL::Long x, WebIDL::Long y, WebIDL::Long width, WebIDL::Long height)
|
|
{
|
|
m_context->make_current();
|
|
glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
|
}
|
|
|
|
GC::Root<WebGLBuffer> WebGLRenderingContextImpl::create_buffer()
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint handle = 0;
|
|
glGenBuffers(1, &handle);
|
|
return WebGLBuffer::create(m_realm, *this, handle);
|
|
}
|
|
|
|
GC::Root<WebGLFramebuffer> WebGLRenderingContextImpl::create_framebuffer()
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint handle = 0;
|
|
glGenFramebuffers(1, &handle);
|
|
return WebGLFramebuffer::create(m_realm, *this, handle);
|
|
}
|
|
|
|
GC::Root<WebGLProgram> WebGLRenderingContextImpl::create_program()
|
|
{
|
|
m_context->make_current();
|
|
return WebGLProgram::create(m_realm, *this, glCreateProgram());
|
|
}
|
|
|
|
GC::Root<WebGLRenderbuffer> WebGLRenderingContextImpl::create_renderbuffer()
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint handle = 0;
|
|
glGenRenderbuffers(1, &handle);
|
|
return WebGLRenderbuffer::create(m_realm, *this, handle);
|
|
}
|
|
|
|
GC::Root<WebGLShader> WebGLRenderingContextImpl::create_shader(WebIDL::UnsignedLong type)
|
|
{
|
|
m_context->make_current();
|
|
|
|
if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) {
|
|
dbgln("Unknown WebGL shader type: 0x{:04x}", type);
|
|
set_error(GL_INVALID_ENUM);
|
|
return nullptr;
|
|
}
|
|
|
|
GLuint handle = glCreateShader(type);
|
|
return WebGLShader::create(m_realm, *this, handle, type);
|
|
}
|
|
|
|
GC::Root<WebGLTexture> WebGLRenderingContextImpl::create_texture()
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint handle = 0;
|
|
glGenTextures(1, &handle);
|
|
return WebGLTexture::create(m_realm, *this, handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::cull_face(WebIDL::UnsignedLong mode)
|
|
{
|
|
m_context->make_current();
|
|
glCullFace(mode);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_buffer(GC::Root<WebGLBuffer> buffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint buffer_handle = 0;
|
|
if (buffer) {
|
|
auto handle_or_error = buffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
buffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glDeleteBuffers(1, &buffer_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_framebuffer(GC::Root<WebGLFramebuffer> framebuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint framebuffer_handle = 0;
|
|
if (framebuffer) {
|
|
auto handle_or_error = framebuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
framebuffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glDeleteFramebuffers(1, &framebuffer_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_program(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
glDeleteProgram(program_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_renderbuffer(GC::Root<WebGLRenderbuffer> renderbuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint renderbuffer_handle = 0;
|
|
if (renderbuffer) {
|
|
auto handle_or_error = renderbuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
renderbuffer_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glDeleteRenderbuffers(1, &renderbuffer_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_shader(GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
glDeleteShader(shader_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::delete_texture(GC::Root<WebGLTexture> texture)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint texture_handle = 0;
|
|
if (texture) {
|
|
auto handle_or_error = texture->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
texture_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glDeleteTextures(1, &texture_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::depth_func(WebIDL::UnsignedLong func)
|
|
{
|
|
m_context->make_current();
|
|
glDepthFunc(func);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::depth_mask(bool flag)
|
|
{
|
|
m_context->make_current();
|
|
glDepthMask(flag);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::depth_range(float z_near, float z_far)
|
|
{
|
|
m_context->make_current();
|
|
glDepthRangef(z_near, z_far);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::detach_shader(GC::Root<WebGLProgram> program, GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
auto shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
glDetachShader(program_handle, shader_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::disable(WebIDL::UnsignedLong cap)
|
|
{
|
|
m_context->make_current();
|
|
glDisable(cap);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::disable_vertex_attrib_array(WebIDL::UnsignedLong index)
|
|
{
|
|
m_context->make_current();
|
|
glDisableVertexAttribArray(index);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::draw_arrays(WebIDL::UnsignedLong mode, WebIDL::Long first, WebIDL::Long count)
|
|
{
|
|
m_context->make_current();
|
|
m_context->notify_content_will_change();
|
|
needs_to_present();
|
|
glDrawArrays(mode, first, count);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::draw_elements(WebIDL::UnsignedLong mode, WebIDL::Long count, WebIDL::UnsignedLong type, WebIDL::LongLong offset)
|
|
{
|
|
m_context->make_current();
|
|
m_context->notify_content_will_change();
|
|
|
|
glDrawElements(mode, count, type, reinterpret_cast<void*>(offset));
|
|
needs_to_present();
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::enable(WebIDL::UnsignedLong cap)
|
|
{
|
|
m_context->make_current();
|
|
glEnable(cap);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::enable_vertex_attrib_array(WebIDL::UnsignedLong index)
|
|
{
|
|
m_context->make_current();
|
|
glEnableVertexAttribArray(index);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::finish()
|
|
{
|
|
m_context->make_current();
|
|
glFinish();
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::flush()
|
|
{
|
|
m_context->make_current();
|
|
glFlush();
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::framebuffer_renderbuffer(WebIDL::UnsignedLong target, WebIDL::UnsignedLong attachment, WebIDL::UnsignedLong renderbuffertarget, GC::Root<WebGLRenderbuffer> renderbuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto renderbuffer_handle = 0;
|
|
if (renderbuffer) {
|
|
auto handle_or_error = renderbuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
renderbuffer_handle = handle_or_error.release_value();
|
|
}
|
|
glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::framebuffer_texture2d(WebIDL::UnsignedLong target, WebIDL::UnsignedLong attachment, WebIDL::UnsignedLong textarget, GC::Root<WebGLTexture> texture, WebIDL::Long level)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto texture_handle = 0;
|
|
if (texture) {
|
|
auto handle_or_error = texture->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
texture_handle = handle_or_error.release_value();
|
|
}
|
|
glFramebufferTexture2D(target, attachment, textarget, texture_handle, level);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::front_face(WebIDL::UnsignedLong mode)
|
|
{
|
|
m_context->make_current();
|
|
glFrontFace(mode);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::generate_mipmap(WebIDL::UnsignedLong target)
|
|
{
|
|
m_context->make_current();
|
|
glGenerateMipmap(target);
|
|
}
|
|
|
|
GC::Root<WebGLActiveInfo> WebGLRenderingContextImpl::get_active_attrib(GC::Root<WebGLProgram> program, WebIDL::UnsignedLong index)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint size = 0;
|
|
GLenum type = 0;
|
|
GLsizei buf_size = 256;
|
|
GLsizei length = 0;
|
|
GLchar name[256];
|
|
glGetActiveAttrib(program_handle, index, buf_size, &length, &size, &type, name);
|
|
auto readonly_bytes = ReadonlyBytes { name, static_cast<size_t>(length) };
|
|
return WebGLActiveInfo::create(m_realm, String::from_utf8_without_validation(readonly_bytes), type, size);
|
|
}
|
|
|
|
GC::Root<WebGLActiveInfo> WebGLRenderingContextImpl::get_active_uniform(GC::Root<WebGLProgram> program, WebIDL::UnsignedLong index)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint size = 0;
|
|
GLenum type = 0;
|
|
GLsizei buf_size = 256;
|
|
GLsizei length = 0;
|
|
GLchar name[256];
|
|
glGetActiveUniform(program_handle, index, buf_size, &length, &size, &type, name);
|
|
auto readonly_bytes = ReadonlyBytes { name, static_cast<size_t>(length) };
|
|
return WebGLActiveInfo::create(m_realm, String::from_utf8_without_validation(readonly_bytes), type, size);
|
|
}
|
|
|
|
Optional<Vector<GC::Root<WebGLShader>>> WebGLRenderingContextImpl::get_attached_shaders(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return OptionalNone {};
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
(void)program_handle;
|
|
|
|
Vector<GC::Root<WebGLShader>> result;
|
|
|
|
if (program->attached_vertex_shader())
|
|
result.append(GC::make_root(*program->attached_vertex_shader()));
|
|
|
|
if (program->attached_fragment_shader())
|
|
result.append(GC::make_root(*program->attached_fragment_shader()));
|
|
|
|
return result;
|
|
}
|
|
|
|
WebIDL::Long WebGLRenderingContextImpl::get_attrib_location(GC::Root<WebGLProgram> program, String name)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return -1;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
auto name_null_terminated = null_terminated_string(name);
|
|
return glGetAttribLocation(program_handle, name_null_terminated.data());
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_buffer_parameter(WebIDL::UnsignedLong target, WebIDL::UnsignedLong pname)
|
|
{
|
|
m_context->make_current();
|
|
switch (pname) {
|
|
case GL_BUFFER_SIZE: {
|
|
GLint result { 0 };
|
|
glGetBufferParameterivRobustANGLE(target, GL_BUFFER_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
case GL_BUFFER_USAGE: {
|
|
GLint result { 0 };
|
|
glGetBufferParameterivRobustANGLE(target, GL_BUFFER_USAGE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
default:
|
|
dbgln("Unknown WebGL buffer parameter name: {:x}", pname);
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_parameter(WebIDL::UnsignedLong pname)
|
|
{
|
|
m_context->make_current();
|
|
switch (pname) {
|
|
case GL_ACTIVE_TEXTURE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_ACTIVE_TEXTURE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_ALIASED_LINE_WIDTH_RANGE: {
|
|
Array<GLfloat, 2> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 2 * sizeof(GLfloat);
|
|
glGetFloatvRobustANGLE(GL_ALIASED_LINE_WIDTH_RANGE, 2, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, 2, array_buffer);
|
|
}
|
|
case GL_ALIASED_POINT_SIZE_RANGE: {
|
|
Array<GLfloat, 2> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 2 * sizeof(GLfloat);
|
|
glGetFloatvRobustANGLE(GL_ALIASED_POINT_SIZE_RANGE, 2, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, 2, array_buffer);
|
|
}
|
|
case GL_ALPHA_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_ALPHA_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_ARRAY_BUFFER_BINDING: {
|
|
if (!m_array_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_array_buffer_binding);
|
|
}
|
|
case GL_BLEND: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_BLEND, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_BLEND_COLOR: {
|
|
Array<GLfloat, 4> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 4 * sizeof(GLfloat);
|
|
glGetFloatvRobustANGLE(GL_BLEND_COLOR, 4, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, 4, array_buffer);
|
|
}
|
|
case GL_BLEND_DST_ALPHA: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_DST_ALPHA, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLEND_DST_RGB: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_DST_RGB, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLEND_EQUATION_ALPHA: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_EQUATION_ALPHA, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLEND_EQUATION_RGB: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_EQUATION_RGB, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLEND_SRC_ALPHA: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_SRC_ALPHA, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLEND_SRC_RGB: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLEND_SRC_RGB, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_BLUE_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_BLUE_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_COLOR_CLEAR_VALUE: {
|
|
Array<GLfloat, 4> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 4 * sizeof(GLfloat);
|
|
glGetFloatvRobustANGLE(GL_COLOR_CLEAR_VALUE, 4, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, 4, array_buffer);
|
|
}
|
|
case GL_CULL_FACE: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_CULL_FACE, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_CULL_FACE_MODE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_CULL_FACE_MODE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_CURRENT_PROGRAM: {
|
|
if (!m_current_program)
|
|
return JS::js_null();
|
|
return JS::Value(m_current_program);
|
|
}
|
|
case GL_DEPTH_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_DEPTH_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_DEPTH_CLEAR_VALUE: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_DEPTH_CLEAR_VALUE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_DEPTH_FUNC: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_DEPTH_FUNC, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_DEPTH_RANGE: {
|
|
Array<GLfloat, 2> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 2 * sizeof(GLfloat);
|
|
glGetFloatvRobustANGLE(GL_DEPTH_RANGE, 2, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, 2, array_buffer);
|
|
}
|
|
case GL_DEPTH_TEST: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_DEPTH_TEST, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_DEPTH_WRITEMASK: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_DEPTH_WRITEMASK, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_DITHER: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_DITHER, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
|
|
if (!m_element_array_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_element_array_buffer_binding);
|
|
}
|
|
case GL_FRAMEBUFFER_BINDING: {
|
|
if (!m_framebuffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_framebuffer_binding);
|
|
}
|
|
case GL_FRONT_FACE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_FRONT_FACE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_GENERATE_MIPMAP_HINT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_GENERATE_MIPMAP_HINT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_GREEN_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_GREEN_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_IMPLEMENTATION_COLOR_READ_FORMAT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_IMPLEMENTATION_COLOR_READ_TYPE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_IMPLEMENTATION_COLOR_READ_TYPE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_LINE_WIDTH: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_LINE_WIDTH, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_CUBE_MAP_TEXTURE_SIZE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_CUBE_MAP_TEXTURE_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_FRAGMENT_UNIFORM_VECTORS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_FRAGMENT_UNIFORM_VECTORS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_RENDERBUFFER_SIZE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_RENDERBUFFER_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TEXTURE_IMAGE_UNITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_TEXTURE_IMAGE_UNITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TEXTURE_SIZE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_TEXTURE_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VARYING_VECTORS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VARYING_VECTORS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_ATTRIBS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_ATTRIBS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_UNIFORM_VECTORS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_UNIFORM_VECTORS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VIEWPORT_DIMS: {
|
|
Array<GLint, 2> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 2 * sizeof(GLint);
|
|
glGetIntegervRobustANGLE(GL_MAX_VIEWPORT_DIMS, 2, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Int32Array::create(m_realm, 2, array_buffer);
|
|
}
|
|
case GL_PACK_ALIGNMENT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_PACK_ALIGNMENT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_POLYGON_OFFSET_FACTOR: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_POLYGON_OFFSET_FACTOR, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_POLYGON_OFFSET_FILL: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_POLYGON_OFFSET_FILL, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_POLYGON_OFFSET_UNITS: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_POLYGON_OFFSET_UNITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_RED_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_RED_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_RENDERBUFFER_BINDING: {
|
|
if (!m_renderbuffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_renderbuffer_binding);
|
|
}
|
|
case GL_RENDERER: {
|
|
auto result = reinterpret_cast<char const*>(glGetString(GL_RENDERER));
|
|
return JS::PrimitiveString::create(m_realm->vm(), ByteString { result });
|
|
}
|
|
case GL_SAMPLE_ALPHA_TO_COVERAGE: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_SAMPLE_ALPHA_TO_COVERAGE, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_SAMPLE_BUFFERS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_SAMPLE_BUFFERS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_SAMPLE_COVERAGE: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_SAMPLE_COVERAGE, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_SAMPLE_COVERAGE_INVERT: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_SAMPLE_COVERAGE_INVERT, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_SAMPLE_COVERAGE_VALUE: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_SAMPLE_COVERAGE_VALUE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_SAMPLES: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_SAMPLES, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_SCISSOR_BOX: {
|
|
Array<GLint, 4> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 4 * sizeof(GLint);
|
|
glGetIntegervRobustANGLE(GL_SCISSOR_BOX, 4, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Int32Array::create(m_realm, 4, array_buffer);
|
|
}
|
|
case GL_SCISSOR_TEST: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_SCISSOR_TEST, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_SHADING_LANGUAGE_VERSION: {
|
|
auto result = reinterpret_cast<char const*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
return JS::PrimitiveString::create(m_realm->vm(), ByteString { result });
|
|
}
|
|
case GL_STENCIL_BACK_FAIL: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_FAIL, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_FUNC: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_FUNC, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_PASS_DEPTH_FAIL: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_PASS_DEPTH_FAIL, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_PASS_DEPTH_PASS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_PASS_DEPTH_PASS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_REF: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_REF, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_VALUE_MASK: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_VALUE_MASK, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BACK_WRITEMASK: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BACK_WRITEMASK, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_CLEAR_VALUE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_CLEAR_VALUE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_FAIL: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_FAIL, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_FUNC: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_FUNC, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_PASS_DEPTH_FAIL: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_PASS_DEPTH_FAIL, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_PASS_DEPTH_PASS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_PASS_DEPTH_PASS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_REF: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_REF, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_TEST: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_STENCIL_TEST, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_STENCIL_VALUE_MASK: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_VALUE_MASK, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_STENCIL_WRITEMASK: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_STENCIL_WRITEMASK, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_SUBPIXEL_BITS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_SUBPIXEL_BITS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_TEXTURE_BINDING_2D: {
|
|
if (!m_texture_binding_2d)
|
|
return JS::js_null();
|
|
return JS::Value(m_texture_binding_2d);
|
|
}
|
|
case GL_TEXTURE_BINDING_CUBE_MAP: {
|
|
if (!m_texture_binding_cube_map)
|
|
return JS::js_null();
|
|
return JS::Value(m_texture_binding_cube_map);
|
|
}
|
|
case GL_UNPACK_ALIGNMENT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_ALIGNMENT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_VENDOR: {
|
|
auto result = reinterpret_cast<char const*>(glGetString(GL_VENDOR));
|
|
return JS::PrimitiveString::create(m_realm->vm(), ByteString { result });
|
|
}
|
|
case GL_VERSION: {
|
|
auto result = reinterpret_cast<char const*>(glGetString(GL_VERSION));
|
|
return JS::PrimitiveString::create(m_realm->vm(), ByteString { result });
|
|
}
|
|
case GL_VIEWPORT: {
|
|
Array<GLint, 4> result;
|
|
result.fill(0);
|
|
constexpr size_t buffer_size = 4 * sizeof(GLint);
|
|
glGetIntegervRobustANGLE(GL_VIEWPORT, 4, nullptr, result.data());
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.data(), buffer_size));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Int32Array::create(m_realm, 4, array_buffer);
|
|
}
|
|
|
|
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) { // FIXME: Allow this code path for GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
case GL_MAX_COLOR_ATTACHMENTS: {
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) { // FIXME: Allow this code path for MAX_COLOR_ATTACHMENTS_WEBGL
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_COLOR_ATTACHMENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
case GL_MAX_DRAW_BUFFERS: {
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) { // FIXME: Allow this code path for MAX_DRAW_BUFFERS_WEBGL
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_DRAW_BUFFERS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: {
|
|
if (ext_texture_filter_anisotropic_extension_enabled()) {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
|
|
case COMPRESSED_TEXTURE_FORMATS: {
|
|
auto formats = enabled_compressed_texture_formats();
|
|
auto byte_buffer = MUST(ByteBuffer::copy(formats.data(), formats.reinterpret<u8 const>().size()));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Uint32Array::create(m_realm, formats.size(), array_buffer);
|
|
}
|
|
case UNPACK_FLIP_Y_WEBGL:
|
|
return JS::Value(m_unpack_flip_y);
|
|
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
|
|
return JS::Value(m_unpack_premultiply_alpha);
|
|
}
|
|
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
switch (pname) {
|
|
case GL_COPY_READ_BUFFER_BINDING: {
|
|
if (!m_copy_read_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_copy_read_buffer_binding);
|
|
}
|
|
case GL_COPY_WRITE_BUFFER_BINDING: {
|
|
if (!m_copy_write_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_copy_write_buffer_binding);
|
|
}
|
|
case GL_MAX_SAMPLES: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_SAMPLES, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_3D_TEXTURE_SIZE: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_3D_TEXTURE_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_ARRAY_TEXTURE_LAYERS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_ARRAY_TEXTURE_LAYERS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_UNIFORM_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_UNIFORM_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_UNIFORM_BLOCK_SIZE: {
|
|
GLint64 result { 0 };
|
|
glGetInteger64vRobustANGLE(GL_MAX_UNIFORM_BLOCK_SIZE, 1, nullptr, &result);
|
|
return JS::Value(static_cast<double>(result));
|
|
}
|
|
case GL_MAX_UNIFORM_BUFFER_BINDINGS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_UNIFORM_BUFFER_BINDINGS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_UNIFORM_BLOCKS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_UNIFORM_BLOCKS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_FRAGMENT_INPUT_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_FRAGMENT_INPUT_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_COMBINED_UNIFORM_BLOCKS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_COMBINED_UNIFORM_BLOCKS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: {
|
|
GLint64 result { 0 };
|
|
glGetInteger64vRobustANGLE(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(static_cast<double>(result));
|
|
}
|
|
case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: {
|
|
GLint64 result { 0 };
|
|
glGetInteger64vRobustANGLE(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(static_cast<double>(result));
|
|
}
|
|
case GL_MAX_ELEMENT_INDEX: {
|
|
GLint64 result { 0 };
|
|
glGetInteger64vRobustANGLE(GL_MAX_ELEMENT_INDEX, 1, nullptr, &result);
|
|
return JS::Value(static_cast<double>(result));
|
|
}
|
|
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VARYING_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VARYING_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_ELEMENTS_INDICES: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_ELEMENTS_INDICES, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_ELEMENTS_VERTICES: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_ELEMENTS_VERTICES, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TEXTURE_LOD_BIAS: {
|
|
GLfloat result { 0.0f };
|
|
glGetFloatvRobustANGLE(GL_MAX_TEXTURE_LOD_BIAS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MIN_PROGRAM_TEXEL_OFFSET: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MIN_PROGRAM_TEXEL_OFFSET, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_PROGRAM_TEXEL_OFFSET: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_PROGRAM_TEXEL_OFFSET, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_VERTEX_OUTPUT_COMPONENTS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_MAX_VERTEX_OUTPUT_COMPONENTS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_MAX_SERVER_WAIT_TIMEOUT: {
|
|
GLint64 result { 0 };
|
|
glGetInteger64vRobustANGLE(GL_MAX_SERVER_WAIT_TIMEOUT, 1, nullptr, &result);
|
|
return JS::Value(static_cast<double>(result));
|
|
}
|
|
case GL_PACK_ROW_LENGTH: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_PACK_ROW_LENGTH, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_PACK_SKIP_ROWS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_PACK_SKIP_ROWS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_PACK_SKIP_PIXELS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_PACK_SKIP_PIXELS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_PIXEL_PACK_BUFFER_BINDING: {
|
|
if (!m_pixel_pack_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_pixel_pack_buffer_binding);
|
|
}
|
|
case GL_PIXEL_UNPACK_BUFFER_BINDING: {
|
|
if (!m_pixel_unpack_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_pixel_unpack_buffer_binding);
|
|
}
|
|
case GL_TEXTURE_BINDING_2D_ARRAY: {
|
|
if (!m_texture_binding_2d_array)
|
|
return JS::js_null();
|
|
return JS::Value(m_texture_binding_2d_array);
|
|
}
|
|
case GL_TRANSFORM_FEEDBACK_ACTIVE: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_TRANSFORM_FEEDBACK_ACTIVE, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_TRANSFORM_FEEDBACK_BINDING: {
|
|
if (!m_transform_feedback_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_transform_feedback_binding);
|
|
}
|
|
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: {
|
|
if (!m_transform_feedback_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_transform_feedback_buffer_binding);
|
|
}
|
|
case GL_TRANSFORM_FEEDBACK_PAUSED: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_TRANSFORM_FEEDBACK_PAUSED, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_RASTERIZER_DISCARD: {
|
|
GLboolean result { GL_FALSE };
|
|
glGetBooleanvRobustANGLE(GL_RASTERIZER_DISCARD, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_SAMPLER_BINDING: {
|
|
GLint handle { 0 };
|
|
glGetIntegervRobustANGLE(GL_SAMPLER_BINDING, 1, nullptr, &handle);
|
|
return WebGLSampler::create(m_realm, *this, handle);
|
|
}
|
|
case GL_UNIFORM_BUFFER_BINDING: {
|
|
if (!m_uniform_buffer_binding)
|
|
return JS::js_null();
|
|
return JS::Value(m_uniform_buffer_binding);
|
|
}
|
|
case GL_UNPACK_IMAGE_HEIGHT: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_IMAGE_HEIGHT, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_UNPACK_ROW_LENGTH: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_ROW_LENGTH, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_UNPACK_SKIP_IMAGES: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_SKIP_IMAGES, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_UNPACK_SKIP_PIXELS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_SKIP_PIXELS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_UNPACK_SKIP_ROWS: {
|
|
GLint result { 0 };
|
|
glGetIntegervRobustANGLE(GL_UNPACK_SKIP_ROWS, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case MAX_CLIENT_WAIT_TIMEOUT_WEBGL:
|
|
// FIXME: Make this an actual limit
|
|
return JS::js_infinity();
|
|
}
|
|
}
|
|
|
|
dbgln("Unknown WebGL parameter name: {:x}", pname);
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
|
|
WebIDL::UnsignedLong WebGLRenderingContextImpl::get_error()
|
|
{
|
|
m_context->make_current();
|
|
return glGetError();
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_program_parameter(GC::Root<WebGLProgram> program, WebIDL::UnsignedLong pname)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return JS::js_null();
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint result = 0;
|
|
glGetProgramivRobustANGLE(program_handle, pname, 1, nullptr, &result);
|
|
switch (pname) {
|
|
case GL_ATTACHED_SHADERS:
|
|
case GL_ACTIVE_ATTRIBUTES:
|
|
case GL_ACTIVE_UNIFORMS:
|
|
return JS::Value(result);
|
|
|
|
case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
|
|
case GL_TRANSFORM_FEEDBACK_VARYINGS:
|
|
case GL_ACTIVE_UNIFORM_BLOCKS:
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2)
|
|
return JS::Value(result);
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
|
|
case GL_DELETE_STATUS:
|
|
case GL_LINK_STATUS:
|
|
case GL_VALIDATE_STATUS:
|
|
return JS::Value(result == GL_TRUE);
|
|
default:
|
|
dbgln("Unknown WebGL program parameter name: 0x{:04x}", pname);
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
}
|
|
|
|
Optional<String> WebGLRenderingContextImpl::get_program_info_log(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint info_log_length = 0;
|
|
glGetProgramiv(program_handle, GL_INFO_LOG_LENGTH, &info_log_length);
|
|
Vector<GLchar> info_log;
|
|
info_log.resize(info_log_length);
|
|
if (!info_log_length)
|
|
return String {};
|
|
glGetProgramInfoLog(program_handle, info_log_length, nullptr, info_log.data());
|
|
return String::from_utf8_without_validation(ReadonlyBytes { info_log.data(), static_cast<size_t>(info_log_length - 1) });
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_shader_parameter(GC::Root<WebGLShader> shader, WebIDL::UnsignedLong pname)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return JS::js_null();
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint result = 0;
|
|
glGetShaderivRobustANGLE(shader_handle, pname, 1, nullptr, &result);
|
|
switch (pname) {
|
|
case GL_SHADER_TYPE:
|
|
return JS::Value(result);
|
|
case GL_DELETE_STATUS:
|
|
case GL_COMPILE_STATUS:
|
|
return JS::Value(result == GL_TRUE);
|
|
default:
|
|
dbgln("Unknown WebGL shader parameter name: 0x{:04x}", pname);
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
}
|
|
|
|
GC::Root<WebGLShaderPrecisionFormat> WebGLRenderingContextImpl::get_shader_precision_format(WebIDL::UnsignedLong shadertype, WebIDL::UnsignedLong precisiontype)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLint range[2];
|
|
GLint precision;
|
|
glGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
|
|
return WebGLShaderPrecisionFormat::create(m_realm, range[0], range[1], precision);
|
|
}
|
|
|
|
Optional<String> WebGLRenderingContextImpl::get_shader_info_log(GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint info_log_length = 0;
|
|
glGetShaderiv(shader_handle, GL_INFO_LOG_LENGTH, &info_log_length);
|
|
Vector<GLchar> info_log;
|
|
info_log.resize(info_log_length);
|
|
if (!info_log_length)
|
|
return String {};
|
|
glGetShaderInfoLog(shader_handle, info_log_length, nullptr, info_log.data());
|
|
return String::from_utf8_without_validation(ReadonlyBytes { info_log.data(), static_cast<size_t>(info_log_length - 1) });
|
|
}
|
|
|
|
Optional<String> WebGLRenderingContextImpl::get_shader_source(GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
GLint shader_source_length = 0;
|
|
glGetShaderiv(shader_handle, GL_SHADER_SOURCE_LENGTH, &shader_source_length);
|
|
if (!shader_source_length)
|
|
return String {};
|
|
|
|
auto shader_source = MUST(ByteBuffer::create_uninitialized(shader_source_length));
|
|
glGetShaderSource(shader_handle, shader_source_length, nullptr, reinterpret_cast<GLchar*>(shader_source.data()));
|
|
return String::from_utf8_without_validation(ReadonlyBytes { shader_source.data(), static_cast<size_t>(shader_source_length - 1) });
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_uniform(GC::Root<WebGLProgram>, GC::Root<WebGLUniformLocation>)
|
|
{
|
|
dbgln("FIXME: Implement get_uniform");
|
|
return JS::Value(0);
|
|
}
|
|
|
|
GC::Root<WebGLUniformLocation> WebGLRenderingContextImpl::get_uniform_location(GC::Root<WebGLProgram> program, String name)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return {};
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
auto name_null_terminated = null_terminated_string(name);
|
|
|
|
// "This function returns -1 if name does not correspond to an active uniform variable in program or if name starts
|
|
// with the reserved prefix "gl_"."
|
|
// WebGL Spec: The return value is null if name does not correspond to an active uniform variable in the passed program.
|
|
auto location = glGetUniformLocation(program_handle, name_null_terminated.data());
|
|
if (location == -1)
|
|
return nullptr;
|
|
|
|
return WebGLUniformLocation::create(m_realm, location);
|
|
}
|
|
|
|
JS::Value WebGLRenderingContextImpl::get_vertex_attrib(WebIDL::UnsignedLong index, WebIDL::UnsignedLong pname)
|
|
{
|
|
switch (pname) {
|
|
case GL_CURRENT_VERTEX_ATTRIB: {
|
|
Array<GLfloat, 4> result;
|
|
result.fill(0);
|
|
glGetVertexAttribfvRobustANGLE(index, GL_CURRENT_VERTEX_ATTRIB, result.size(), nullptr, result.data());
|
|
|
|
auto byte_buffer = MUST(ByteBuffer::copy(result.span().reinterpret<u8>()));
|
|
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(byte_buffer));
|
|
return JS::Float32Array::create(m_realm, result.size(), array_buffer);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
|
|
GLint handle { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 1, nullptr, &handle);
|
|
return WebGLBuffer::create(m_realm, *this, handle);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: { // NOTE: This has the same value as GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE
|
|
if (angle_instanced_arrays_extension_enabled() || m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_ENABLED: {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: {
|
|
if (m_context->webgl_version() == OpenGLContext::WebGLVersion::WebGL2) {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_INTEGER, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 1, nullptr, &result);
|
|
return JS::Value(result == GL_TRUE);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_SIZE: {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_STRIDE: {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
case GL_VERTEX_ATTRIB_ARRAY_TYPE: {
|
|
GLint result { 0 };
|
|
glGetVertexAttribivRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, 1, nullptr, &result);
|
|
return JS::Value(result);
|
|
}
|
|
default:
|
|
dbgln("Unknown WebGL vertex attrib name: 0x{:04x}", pname);
|
|
set_error(GL_INVALID_ENUM);
|
|
return JS::js_null();
|
|
}
|
|
}
|
|
|
|
WebIDL::LongLong WebGLRenderingContextImpl::get_vertex_attrib_offset(WebIDL::UnsignedLong index, WebIDL::UnsignedLong pname)
|
|
{
|
|
if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) {
|
|
set_error(GL_INVALID_ENUM);
|
|
return 0;
|
|
}
|
|
|
|
GLintptr result { 0 };
|
|
glGetVertexAttribPointervRobustANGLE(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, 1, nullptr, reinterpret_cast<void**>(&result));
|
|
return result;
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::hint(WebIDL::UnsignedLong target, WebIDL::UnsignedLong mode)
|
|
{
|
|
m_context->make_current();
|
|
glHint(target, mode);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_buffer(GC::Root<WebGLBuffer> buffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto buffer_handle = 0;
|
|
if (buffer) {
|
|
auto handle_or_error = buffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
buffer_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsBuffer(buffer_handle);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_enabled(WebIDL::UnsignedLong cap)
|
|
{
|
|
m_context->make_current();
|
|
return glIsEnabled(cap);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_framebuffer(GC::Root<WebGLFramebuffer> framebuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto framebuffer_handle = 0;
|
|
if (framebuffer) {
|
|
auto handle_or_error = framebuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
framebuffer_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsFramebuffer(framebuffer_handle);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_program(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsProgram(program_handle);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_renderbuffer(GC::Root<WebGLRenderbuffer> renderbuffer)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto renderbuffer_handle = 0;
|
|
if (renderbuffer) {
|
|
auto handle_or_error = renderbuffer->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
renderbuffer_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsRenderbuffer(renderbuffer_handle);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_shader(GC::Root<WebGLShader> shader)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsShader(shader_handle);
|
|
}
|
|
|
|
bool WebGLRenderingContextImpl::is_texture(GC::Root<WebGLTexture> texture)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto texture_handle = 0;
|
|
if (texture) {
|
|
auto handle_or_error = texture->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return false;
|
|
}
|
|
texture_handle = handle_or_error.release_value();
|
|
}
|
|
return glIsTexture(texture_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::line_width(float width)
|
|
{
|
|
m_context->make_current();
|
|
glLineWidth(width);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::link_program(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
glLinkProgram(program_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::pixel_storei(WebIDL::UnsignedLong pname, WebIDL::Long param)
|
|
{
|
|
m_context->make_current();
|
|
|
|
switch (pname) {
|
|
case UNPACK_FLIP_Y_WEBGL:
|
|
m_unpack_flip_y = param != GL_FALSE;
|
|
return;
|
|
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
|
|
m_unpack_premultiply_alpha = param != GL_FALSE;
|
|
return;
|
|
}
|
|
|
|
glPixelStorei(pname, param);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::polygon_offset(float factor, float units)
|
|
{
|
|
m_context->make_current();
|
|
glPolygonOffset(factor, units);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::renderbuffer_storage(WebIDL::UnsignedLong target, WebIDL::UnsignedLong internalformat, WebIDL::Long width, WebIDL::Long height)
|
|
{
|
|
m_context->make_current();
|
|
|
|
if (internalformat == GL_DEPTH_STENCIL)
|
|
internalformat = GL_DEPTH24_STENCIL8;
|
|
|
|
glRenderbufferStorage(target, internalformat, width, height);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::sample_coverage(float value, bool invert)
|
|
{
|
|
m_context->make_current();
|
|
glSampleCoverage(value, invert);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::scissor(WebIDL::Long x, WebIDL::Long y, WebIDL::Long width, WebIDL::Long height)
|
|
{
|
|
m_context->make_current();
|
|
glScissor(x, y, width, height);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::shader_source(GC::Root<WebGLShader> shader, String source)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint shader_handle = 0;
|
|
if (shader) {
|
|
auto handle_or_error = shader->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
shader_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
Vector<GLchar*> strings;
|
|
auto string = null_terminated_string(source);
|
|
strings.append(string.data());
|
|
Vector<GLint> length;
|
|
length.append(source.bytes().size());
|
|
glShaderSource(shader_handle, 1, strings.data(), length.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_func(WebIDL::UnsignedLong func, WebIDL::Long ref, WebIDL::UnsignedLong mask)
|
|
{
|
|
m_context->make_current();
|
|
glStencilFunc(func, ref, mask);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_func_separate(WebIDL::UnsignedLong face, WebIDL::UnsignedLong func, WebIDL::Long ref, WebIDL::UnsignedLong mask)
|
|
{
|
|
m_context->make_current();
|
|
glStencilFuncSeparate(face, func, ref, mask);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_mask(WebIDL::UnsignedLong mask)
|
|
{
|
|
m_context->make_current();
|
|
glStencilMask(mask);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_mask_separate(WebIDL::UnsignedLong face, WebIDL::UnsignedLong mask)
|
|
{
|
|
m_context->make_current();
|
|
glStencilMaskSeparate(face, mask);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_op(WebIDL::UnsignedLong fail, WebIDL::UnsignedLong zfail, WebIDL::UnsignedLong zpass)
|
|
{
|
|
m_context->make_current();
|
|
glStencilOp(fail, zfail, zpass);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::stencil_op_separate(WebIDL::UnsignedLong face, WebIDL::UnsignedLong fail, WebIDL::UnsignedLong zfail, WebIDL::UnsignedLong zpass)
|
|
{
|
|
m_context->make_current();
|
|
glStencilOpSeparate(face, fail, zfail, zpass);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::tex_parameterf(WebIDL::UnsignedLong target, WebIDL::UnsignedLong pname, float param)
|
|
{
|
|
m_context->make_current();
|
|
glTexParameterf(target, pname, param);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::tex_parameteri(WebIDL::UnsignedLong target, WebIDL::UnsignedLong pname, WebIDL::Long param)
|
|
{
|
|
m_context->make_current();
|
|
glTexParameteri(target, pname, param);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform1f(GC::Root<WebGLUniformLocation> location, float x)
|
|
{
|
|
m_context->make_current();
|
|
glUniform1f(location ? location->handle() : 0, x);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform2f(GC::Root<WebGLUniformLocation> location, float x, float y)
|
|
{
|
|
m_context->make_current();
|
|
glUniform2f(location ? location->handle() : 0, x, y);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform3f(GC::Root<WebGLUniformLocation> location, float x, float y, float z)
|
|
{
|
|
m_context->make_current();
|
|
glUniform3f(location ? location->handle() : 0, x, y, z);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform4f(GC::Root<WebGLUniformLocation> location, float x, float y, float z, float w)
|
|
{
|
|
m_context->make_current();
|
|
glUniform4f(location ? location->handle() : 0, x, y, z, w);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform1i(GC::Root<WebGLUniformLocation> location, WebIDL::Long x)
|
|
{
|
|
m_context->make_current();
|
|
glUniform1i(location ? location->handle() : 0, x);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform2i(GC::Root<WebGLUniformLocation> location, WebIDL::Long x, WebIDL::Long y)
|
|
{
|
|
m_context->make_current();
|
|
glUniform2i(location ? location->handle() : 0, x, y);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform3i(GC::Root<WebGLUniformLocation> location, WebIDL::Long x, WebIDL::Long y, WebIDL::Long z)
|
|
{
|
|
m_context->make_current();
|
|
glUniform3i(location ? location->handle() : 0, x, y, z);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::uniform4i(GC::Root<WebGLUniformLocation> location, WebIDL::Long x, WebIDL::Long y, WebIDL::Long z, WebIDL::Long w)
|
|
{
|
|
m_context->make_current();
|
|
glUniform4i(location ? location->handle() : 0, x, y, z, w);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::use_program(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
GLuint program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
|
|
glUseProgram(program_handle);
|
|
m_current_program = program;
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::validate_program(GC::Root<WebGLProgram> program)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto program_handle = 0;
|
|
if (program) {
|
|
auto handle_or_error = program->handle(this);
|
|
if (handle_or_error.is_error()) {
|
|
set_error(GL_INVALID_OPERATION);
|
|
return;
|
|
}
|
|
program_handle = handle_or_error.release_value();
|
|
}
|
|
glValidateProgram(program_handle);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib1f(WebIDL::UnsignedLong index, float x)
|
|
{
|
|
m_context->make_current();
|
|
glVertexAttrib1f(index, x);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib2f(WebIDL::UnsignedLong index, float x, float y)
|
|
{
|
|
m_context->make_current();
|
|
glVertexAttrib2f(index, x, y);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib3f(WebIDL::UnsignedLong index, float x, float y, float z)
|
|
{
|
|
m_context->make_current();
|
|
glVertexAttrib3f(index, x, y, z);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib4f(WebIDL::UnsignedLong index, float x, float y, float z, float w)
|
|
{
|
|
m_context->make_current();
|
|
glVertexAttrib4f(index, x, y, z, w);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib1fv(WebIDL::UnsignedLong index, Float32List values)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto span = MUST(span_from_float32_list(values, /* src_offset= */ 0));
|
|
if (span.size() < 1) {
|
|
set_error(GL_INVALID_VALUE);
|
|
return;
|
|
}
|
|
glVertexAttrib1fv(index, span.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib2fv(WebIDL::UnsignedLong index, Float32List values)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto span = MUST(span_from_float32_list(values, /* src_offset= */ 0));
|
|
if (span.size() < 2) {
|
|
set_error(GL_INVALID_VALUE);
|
|
return;
|
|
}
|
|
glVertexAttrib2fv(index, span.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib3fv(WebIDL::UnsignedLong index, Float32List values)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto span = MUST(span_from_float32_list(values, /* src_offset= */ 0));
|
|
if (span.size() < 3) {
|
|
set_error(GL_INVALID_VALUE);
|
|
return;
|
|
}
|
|
glVertexAttrib3fv(index, span.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib4fv(WebIDL::UnsignedLong index, Float32List values)
|
|
{
|
|
m_context->make_current();
|
|
|
|
auto span = MUST(span_from_float32_list(values, /* src_offset= */ 0));
|
|
if (span.size() < 4) {
|
|
set_error(GL_INVALID_VALUE);
|
|
return;
|
|
}
|
|
glVertexAttrib4fv(index, span.data());
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::vertex_attrib_pointer(WebIDL::UnsignedLong index, WebIDL::Long size, WebIDL::UnsignedLong type, bool normalized, WebIDL::Long stride, WebIDL::LongLong offset)
|
|
{
|
|
m_context->make_current();
|
|
|
|
glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<void*>(offset));
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::viewport(WebIDL::Long x, WebIDL::Long y, WebIDL::Long width, WebIDL::Long height)
|
|
{
|
|
m_context->make_current();
|
|
glViewport(x, y, width, height);
|
|
}
|
|
|
|
void WebGLRenderingContextImpl::visit_edges(JS::Cell::Visitor& visitor)
|
|
{
|
|
visitor.visit(m_realm);
|
|
visitor.visit(m_array_buffer_binding);
|
|
visitor.visit(m_element_array_buffer_binding);
|
|
visitor.visit(m_current_program);
|
|
visitor.visit(m_framebuffer_binding);
|
|
visitor.visit(m_renderbuffer_binding);
|
|
visitor.visit(m_texture_binding_2d);
|
|
visitor.visit(m_texture_binding_cube_map);
|
|
|
|
visitor.visit(m_uniform_buffer_binding);
|
|
visitor.visit(m_copy_read_buffer_binding);
|
|
visitor.visit(m_copy_write_buffer_binding);
|
|
visitor.visit(m_transform_feedback_buffer_binding);
|
|
visitor.visit(m_texture_binding_2d_array);
|
|
visitor.visit(m_texture_binding_3d);
|
|
visitor.visit(m_transform_feedback_binding);
|
|
visitor.visit(m_pixel_pack_buffer_binding);
|
|
visitor.visit(m_pixel_unpack_buffer_binding);
|
|
}
|
|
|
|
}
|