diff --git a/fixtures/html/webgl-conformance/getparameter-binding-test.html b/fixtures/html/webgl-conformance/getparameter-binding-test.html
new file mode 100644
index 000000000..bcb898805
--- /dev/null
+++ b/fixtures/html/webgl-conformance/getparameter-binding-test.html
@@ -0,0 +1,68 @@
+
+
+
+
+ WebGL getParameter Binding Test
+
+
+
+ WebGL getParameter Binding Test
+ This test verifies that context.getParameter() returns null (not undefined) for binding parameters.
+
+
+
+
diff --git a/src/client/graphics/webgl_context.cpp b/src/client/graphics/webgl_context.cpp
index 9e60d485b..6349d3434 100644
--- a/src/client/graphics/webgl_context.cpp
+++ b/src/client/graphics/webgl_context.cpp
@@ -1466,6 +1466,40 @@ namespace endor
return v;
}
+ shared_ptr WebGLContext::getParameter(WebGLBufferBindingParameterName pname)
+ {
+ switch (pname)
+ {
+ case WebGLBufferBindingParameterName::kArrayBufferBinding:
+ return clientState_.vertexBuffer.value_or(nullptr);
+ case WebGLBufferBindingParameterName::kElementArrayBufferBinding:
+ return clientState_.elementBuffer.value_or(nullptr);
+ default:
+ return nullptr;
+ }
+ }
+
+ shared_ptr WebGLContext::getParameterProgram(WebGLObjectBindingParameterName pname)
+ {
+ if (pname == WebGLObjectBindingParameterName::kCurrentProgram)
+ return clientState_.program.value_or(nullptr);
+ return nullptr;
+ }
+
+ shared_ptr WebGLContext::getParameterFramebuffer(WebGLObjectBindingParameterName pname)
+ {
+ if (pname == WebGLObjectBindingParameterName::kFramebufferBinding)
+ return clientState_.framebuffer.value_or(nullptr);
+ return nullptr;
+ }
+
+ shared_ptr WebGLContext::getParameterRenderbuffer(WebGLObjectBindingParameterName pname)
+ {
+ if (pname == WebGLObjectBindingParameterName::kRenderbufferBinding)
+ return clientState_.renderbuffer.value_or(nullptr);
+ return nullptr;
+ }
+
WebGLShaderPrecisionFormat WebGLContext::getShaderPrecisionFormat(int shadertype, int precisiontype)
{
if (shadertype != WEBGL_VERTEX_SHADER && shadertype != WEBGL_FRAGMENT_SHADER)
@@ -2038,6 +2072,42 @@ namespace endor
return v;
}
+ shared_ptr WebGL2Context::getParameterV2(WebGL2BufferBindingParameterName pname)
+ {
+ // These buffer bindings are not yet tracked in clientState
+ // TODO: Extend WebGLState to track additional buffer binding points
+ switch (pname)
+ {
+ case WebGL2BufferBindingParameterName::kCopyReadBufferBinding:
+ case WebGL2BufferBindingParameterName::kCopyWriteBufferBinding:
+ case WebGL2BufferBindingParameterName::kPixelPackBufferBinding:
+ case WebGL2BufferBindingParameterName::kPixelUnpackBufferBinding:
+ case WebGL2BufferBindingParameterName::kTransformFeedbackBufferBinding:
+ case WebGL2BufferBindingParameterName::kUniformBufferBinding:
+ default:
+ return nullptr;
+ }
+ }
+
+ shared_ptr WebGL2Context::getParameterFramebufferV2(WebGL2ObjectBindingParameterName pname)
+ {
+ switch (pname)
+ {
+ case WebGL2ObjectBindingParameterName::kDrawFramebufferBinding:
+ case WebGL2ObjectBindingParameterName::kReadFramebufferBinding:
+ return clientState_.framebuffer.value_or(nullptr);
+ default:
+ return nullptr;
+ }
+ }
+
+ shared_ptr WebGL2Context::getParameterVertexArrayV2(WebGL2ObjectBindingParameterName pname)
+ {
+ if (pname == WebGL2ObjectBindingParameterName::kVertexArrayBinding)
+ return clientState_.vertexArray.value_or(nullptr);
+ return nullptr;
+ }
+
shared_ptr WebGL2Context::getQuery(WebGLQueryTarget target, int pname)
{
NOT_IMPLEMENTED();
diff --git a/src/client/graphics/webgl_context.hpp b/src/client/graphics/webgl_context.hpp
index 32567de43..3e02da007 100644
--- a/src/client/graphics/webgl_context.hpp
+++ b/src/client/graphics/webgl_context.hpp
@@ -219,6 +219,41 @@ namespace endor
kExtMaxViewsOvr = WEBGL2_EXT_MAX_VIEWS_OVR,
};
+ /**
+ * Enum for buffer/object binding parameters that return WebGL objects.
+ */
+ enum class WebGLBufferBindingParameterName
+ {
+ kArrayBufferBinding = WEBGL_ARRAY_BUFFER_BINDING,
+ kElementArrayBufferBinding = WEBGL_ELEMENT_ARRAY_BUFFER_BINDING,
+ };
+
+ enum class WebGLObjectBindingParameterName
+ {
+ kCurrentProgram = WEBGL_CURRENT_PROGRAM,
+ kFramebufferBinding = WEBGL_FRAMEBUFFER_BINDING,
+ kRenderbufferBinding = WEBGL_RENDERBUFFER_BINDING,
+ };
+
+ enum class WebGL2BufferBindingParameterName
+ {
+ kCopyReadBufferBinding = WEBGL2_COPY_READ_BUFFER_BINDING,
+ kCopyWriteBufferBinding = WEBGL2_COPY_WRITE_BUFFER_BINDING,
+ kPixelPackBufferBinding = WEBGL2_PIXEL_PACK_BUFFER_BINDING,
+ kPixelUnpackBufferBinding = WEBGL2_PIXEL_UNPACK_BUFFER_BINDING,
+ kTransformFeedbackBufferBinding = WEBGL2_TRANSFORM_FEEDBACK_BUFFER_BINDING,
+ kUniformBufferBinding = WEBGL2_UNIFORM_BUFFER_BINDING,
+ };
+
+ enum class WebGL2ObjectBindingParameterName
+ {
+ kDrawFramebufferBinding = WEBGL2_DRAW_FRAMEBUFFER_BINDING,
+ kReadFramebufferBinding = WEBGL2_READ_FRAMEBUFFER_BINDING,
+ kVertexArrayBinding = WEBGL2_VERTEX_ARRAY_BINDING,
+ kSamplerBinding = WEBGL2_SAMPLER_BINDING,
+ kTransformFeedbackBinding = WEBGL2_TRANSFORM_FEEDBACK_BINDING,
+ };
+
class ContextAttributes final
{
public:
@@ -464,6 +499,10 @@ namespace endor
bool getParameter(WebGLBooleanIndexedParameterName pname, int index);
float getParameter(WebGLFloatArrayParameterName pname, int index);
std::string getParameter(WebGLStringParameterName pname);
+ std::shared_ptr getParameter(WebGLBufferBindingParameterName pname);
+ std::shared_ptr getParameterProgram(WebGLObjectBindingParameterName pname);
+ std::shared_ptr getParameterFramebuffer(WebGLObjectBindingParameterName pname);
+ std::shared_ptr getParameterRenderbuffer(WebGLObjectBindingParameterName pname);
WebGLShaderPrecisionFormat getShaderPrecisionFormat(int shadertype, int precisiontype);
int getError();
std::vector &getSupportedExtensions();
@@ -728,7 +767,8 @@ namespace endor
/**
* @returns the client state of the WebGL context.
*/
- WebGLState &clientState()
+ // Read-only accessor
+ const WebGLState &clientState() const
{
return clientState_;
}
@@ -917,6 +957,9 @@ namespace endor
std::optional length = std::nullopt);
int getFragDataLocation(std::shared_ptr program, const std::string &name);
int getParameterV2(WebGL2IntegerParameterName pname);
+ std::shared_ptr getParameterV2(WebGL2BufferBindingParameterName pname);
+ std::shared_ptr getParameterFramebufferV2(WebGL2ObjectBindingParameterName pname);
+ std::shared_ptr getParameterVertexArrayV2(WebGL2ObjectBindingParameterName pname);
std::shared_ptr getQuery(WebGLQueryTarget target, int pname);
int getUniformBlockIndex(std::shared_ptr program, const std::string &uniformBlockName);
diff --git a/src/client/script_bindings/webgl/webgl_rendering_context.cpp b/src/client/script_bindings/webgl/webgl_rendering_context.cpp
index 7c9351388..7d10a56ca 100644
--- a/src/client/script_bindings/webgl/webgl_rendering_context.cpp
+++ b/src/client/script_bindings/webgl/webgl_rendering_context.cpp
@@ -4385,6 +4385,61 @@ namespace endor
jsValue = String::NewFromUtf8(isolate, value.c_str()).ToLocalChecked();
break;
}
+ /**
+ * WebGL object bindings (return null when nothing bound, object when bound)
+ */
+ case WEBGL_ARRAY_BUFFER_BINDING:
+ {
+ auto value = handle()->getParameter(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLBuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL_ELEMENT_ARRAY_BUFFER_BINDING:
+ {
+ auto value = handle()->getParameter(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLBuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL_FRAMEBUFFER_BINDING:
+ {
+ auto value = handle()->getParameterFramebuffer(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLFramebuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL_RENDERBUFFER_BINDING:
+ {
+ auto value = handle()->getParameterRenderbuffer(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLRenderbuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL_CURRENT_PROGRAM:
+ {
+ auto value = handle()->getParameterProgram(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLProgram::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL_TEXTURE_BINDING_2D:
+ case WEBGL_TEXTURE_BINDING_CUBE_MAP:
+ {
+ // TODO: Texture bindings not yet tracked in clientState
+ jsValue = Null(isolate);
+ break;
+ }
default:
cerr << "WebGLRenderingContext::GetParameter: Unhandled pname " << pname << endl;
break;
@@ -4429,6 +4484,60 @@ namespace endor
jsValue = Integer::New(isolate, value);
break;
}
+ /**
+ * WebGL2 object bindings (return null when nothing bound, object when bound)
+ */
+ case WEBGL2_VERTEX_ARRAY_BINDING:
+ {
+ auto value = handle()
+ ->getParameterVertexArrayV2(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLVertexArray::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL2_DRAW_FRAMEBUFFER_BINDING:
+ case WEBGL2_READ_FRAMEBUFFER_BINDING:
+ {
+ auto value = handle()
+ ->getParameterFramebufferV2(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLFramebuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL2_COPY_READ_BUFFER_BINDING:
+ case WEBGL2_COPY_WRITE_BUFFER_BINDING:
+ case WEBGL2_PIXEL_PACK_BUFFER_BINDING:
+ case WEBGL2_PIXEL_UNPACK_BUFFER_BINDING:
+ case WEBGL2_UNIFORM_BUFFER_BINDING:
+ case WEBGL2_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ {
+ auto value = handle()
+ ->getParameterV2(static_cast(pname));
+ if (value != nullptr)
+ jsValue = WebGLBuffer::NewInstance(isolate, value);
+ else
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL2_SAMPLER_BINDING:
+ case WEBGL2_TRANSFORM_FEEDBACK_BINDING:
+ {
+ // TODO: Sampler and transform feedback bindings not yet tracked
+ // Would require creating WebGLSampler and WebGLTransformFeedback JavaScript bindings
+ jsValue = Null(isolate);
+ break;
+ }
+ case WEBGL2_TEXTURE_BINDING_2D_ARRAY:
+ case WEBGL2_TEXTURE_BINDING_3D:
+ {
+ // TODO: Texture bindings not yet tracked in clientState
+ jsValue = Null(isolate);
+ break;
+ }
default:
break;
}