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; }