diff --git a/src/client/graphics/webgl_context.cpp b/src/client/graphics/webgl_context.cpp index d71e91c3c..ac224b851 100644 --- a/src/client/graphics/webgl_context.cpp +++ b/src/client/graphics/webgl_context.cpp @@ -1968,6 +1968,22 @@ namespace endor return -1; } + vector WebGL2Context::getInternalformatParameter(uint32_t target, uint32_t internalformat, uint32_t pname) + { + // Query the underlying GL implementation via command buffer + auto req = GetInternalformatParameterCommandBufferRequest(target, internalformat, pname); + sendCommandBufferRequest(req, true); + auto response = recvResponse( + COMMAND_BUFFER_GET_INTERNALFORMAT_PARAMETER_RES, + req); + + if (response == nullptr) [[unlikely]] + { + throw runtime_error("Failed to get internal format parameter: timeout."); + } + return response->values; + } + int WebGL2Context::getParameterV2(WebGL2IntegerParameterName pname) { /** diff --git a/src/client/graphics/webgl_context.hpp b/src/client/graphics/webgl_context.hpp index ae034207c..17433a9e4 100644 --- a/src/client/graphics/webgl_context.hpp +++ b/src/client/graphics/webgl_context.hpp @@ -917,6 +917,7 @@ namespace endor std::optional dstOffset = std::nullopt, std::optional length = std::nullopt); int getFragDataLocation(std::shared_ptr program, const std::string &name); + std::vector getInternalformatParameter(uint32_t target, uint32_t internalformat, uint32_t pname); int getParameterV2(WebGL2IntegerParameterName 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/active_info.cpp b/src/client/script_bindings/webgl/active_info.cpp index c0f9d3e81..803ffe763 100644 --- a/src/client/script_bindings/webgl/active_info.cpp +++ b/src/client/script_bindings/webgl/active_info.cpp @@ -60,5 +60,5 @@ namespace endor } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/active_info.hpp b/src/client/script_bindings/webgl/active_info.hpp index b125c893c..c2d6c9080 100644 --- a/src/client/script_bindings/webgl/active_info.hpp +++ b/src/client/script_bindings/webgl/active_info.hpp @@ -38,5 +38,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/framebuffer.cpp b/src/client/script_bindings/webgl/framebuffer.cpp index dbe790869..d38e0687c 100644 --- a/src/client/script_bindings/webgl/framebuffer.cpp +++ b/src/client/script_bindings/webgl/framebuffer.cpp @@ -31,5 +31,5 @@ namespace endor { } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/framebuffer.hpp b/src/client/script_bindings/webgl/framebuffer.hpp index c54189e65..fd3ab4ec2 100644 --- a/src/client/script_bindings/webgl/framebuffer.hpp +++ b/src/client/script_bindings/webgl/framebuffer.hpp @@ -37,5 +37,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/object.cpp b/src/client/script_bindings/webgl/object.cpp index b03f846b5..78779213d 100644 --- a/src/client/script_bindings/webgl/object.cpp +++ b/src/client/script_bindings/webgl/object.cpp @@ -28,5 +28,5 @@ namespace endor // WebGLObject is a base class, typically not instantiated directly } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/object.hpp b/src/client/script_bindings/webgl/object.hpp index cd48b93ae..f69bb78c8 100644 --- a/src/client/script_bindings/webgl/object.hpp +++ b/src/client/script_bindings/webgl/object.hpp @@ -45,5 +45,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/program.cpp b/src/client/script_bindings/webgl/program.cpp index e4a68a6f8..8c21d7e26 100644 --- a/src/client/script_bindings/webgl/program.cpp +++ b/src/client/script_bindings/webgl/program.cpp @@ -20,5 +20,5 @@ namespace endor } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/program.hpp b/src/client/script_bindings/webgl/program.hpp index ede29c134..0971e7271 100644 --- a/src/client/script_bindings/webgl/program.hpp +++ b/src/client/script_bindings/webgl/program.hpp @@ -32,5 +32,5 @@ namespace endor WebGLProgram(v8::Isolate *isolate, const v8::FunctionCallbackInfo &args); }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/renderbuffer.cpp b/src/client/script_bindings/webgl/renderbuffer.cpp index 7f512b63d..d858602e8 100644 --- a/src/client/script_bindings/webgl/renderbuffer.cpp +++ b/src/client/script_bindings/webgl/renderbuffer.cpp @@ -19,5 +19,5 @@ namespace endor // WebGLRenderbuffer objects are created by WebGL context, not by user code } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/renderbuffer.hpp b/src/client/script_bindings/webgl/renderbuffer.hpp index a9651c800..581ff1b2e 100644 --- a/src/client/script_bindings/webgl/renderbuffer.hpp +++ b/src/client/script_bindings/webgl/renderbuffer.hpp @@ -33,5 +33,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/texture.cpp b/src/client/script_bindings/webgl/texture.cpp index 3b51f5dfa..3d034839c 100644 --- a/src/client/script_bindings/webgl/texture.cpp +++ b/src/client/script_bindings/webgl/texture.cpp @@ -27,5 +27,5 @@ namespace endor { } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/texture.hpp b/src/client/script_bindings/webgl/texture.hpp index b40acad08..9272d305c 100644 --- a/src/client/script_bindings/webgl/texture.hpp +++ b/src/client/script_bindings/webgl/texture.hpp @@ -45,5 +45,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/uniform_location.cpp b/src/client/script_bindings/webgl/uniform_location.cpp index 597a73e97..ce71bd5d6 100644 --- a/src/client/script_bindings/webgl/uniform_location.cpp +++ b/src/client/script_bindings/webgl/uniform_location.cpp @@ -47,5 +47,5 @@ namespace endor } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/uniform_location.hpp b/src/client/script_bindings/webgl/uniform_location.hpp index a5e7de1f2..a1f98b66d 100644 --- a/src/client/script_bindings/webgl/uniform_location.hpp +++ b/src/client/script_bindings/webgl/uniform_location.hpp @@ -44,5 +44,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/vertex_array.cpp b/src/client/script_bindings/webgl/vertex_array.cpp index 3e6ed5f0a..48e8e644b 100644 --- a/src/client/script_bindings/webgl/vertex_array.cpp +++ b/src/client/script_bindings/webgl/vertex_array.cpp @@ -20,5 +20,5 @@ namespace endor { } } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor diff --git a/src/client/script_bindings/webgl/vertex_array.hpp b/src/client/script_bindings/webgl/vertex_array.hpp index 7ba162aa3..a4a03cc1d 100644 --- a/src/client/script_bindings/webgl/vertex_array.hpp +++ b/src/client/script_bindings/webgl/vertex_array.hpp @@ -33,5 +33,5 @@ namespace endor }; } // namespace webgl - } // namespace script_bindings + } // namespace script_bindings } // namespace endor \ No newline at end of file diff --git a/src/client/script_bindings/webgl/webgl2_rendering_context.cpp b/src/client/script_bindings/webgl/webgl2_rendering_context.cpp index f6797d1d1..9d8ff9faf 100644 --- a/src/client/script_bindings/webgl/webgl2_rendering_context.cpp +++ b/src/client/script_bindings/webgl/webgl2_rendering_context.cpp @@ -418,6 +418,7 @@ namespace endor // Enhanced framebuffer operations ADD_WEBGL2_METHOD("blitFramebuffer", BlitFramebuffer) ADD_WEBGL2_METHOD("renderbufferStorageMultisample", RenderbufferStorageMultisample) + ADD_WEBGL2_METHOD("getInternalformatParameter", GetInternalformatParameter) ADD_WEBGL2_METHOD("framebufferTextureLayer", FramebufferTextureLayer) // Enhanced texture operations @@ -1703,6 +1704,56 @@ namespace endor args.GetReturnValue().SetUndefined(); } + void WebGL2RenderingContext::GetInternalformatParameter(const FunctionCallbackInfo &args) + { + Isolate *isolate = args.GetIsolate(); + HandleScope scope(isolate); + Local context = isolate->GetCurrentContext(); + + if (args.Length() < 3) + { + isolate->ThrowException(Exception::TypeError( + MakeMethodArgCountError(isolate, "getInternalformatParameter", 3, args.Length()))); + return; + } + + for (int i = 0; i < 3; ++i) + { + if (!args[i]->IsNumber()) + { + isolate->ThrowException(Exception::TypeError( + MakeMethodArgTypeError(isolate, "getInternalformatParameter", i, "number", args[i]))); + return; + } + } + + uint32_t target = args[0]->Uint32Value(context).ToChecked(); + uint32_t internalformat = args[1]->Uint32Value(context).ToChecked(); + uint32_t pname = args[2]->Uint32Value(context).ToChecked(); + + // Delegate to WebGL2Context for the actual query + auto values = handle()->getInternalformatParameter(target, internalformat, pname); + + // If empty vector returned, it means unsupported pname - return null per spec + if (values.empty()) + { + args.GetReturnValue().SetNull(); + return; + } + + // Create Int32Array to return the values + auto arraybuffer = ArrayBuffer::New(isolate, sizeof(int32_t) * values.size()); + auto backingStore = arraybuffer->GetBackingStore(); + int32_t *data = static_cast(backingStore->Data()); + for (size_t i = 0; i < values.size(); i++) + { + data[i] = values[i]; + } + + Local result = Int32Array::New(arraybuffer, 0, values.size()); + args.GetReturnValue().Set(result); + } + void WebGL2RenderingContext::FramebufferTextureLayer(const v8::FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); diff --git a/src/client/script_bindings/webgl/webgl2_rendering_context.hpp b/src/client/script_bindings/webgl/webgl2_rendering_context.hpp index faf38623b..a09b1060a 100644 --- a/src/client/script_bindings/webgl/webgl2_rendering_context.hpp +++ b/src/client/script_bindings/webgl/webgl2_rendering_context.hpp @@ -100,6 +100,7 @@ namespace endor // Enhanced framebuffer operations void BlitFramebuffer(const v8::FunctionCallbackInfo &args); void RenderbufferStorageMultisample(const v8::FunctionCallbackInfo &args); + void GetInternalformatParameter(const v8::FunctionCallbackInfo &args); void FramebufferTextureLayer(const v8::FunctionCallbackInfo &args); // Enhanced texture operations diff --git a/src/common/command_buffers/details/properties.hpp b/src/common/command_buffers/details/properties.hpp index 854ed4466..b2341092b 100644 --- a/src/common/command_buffers/details/properties.hpp +++ b/src/common/command_buffers/details/properties.hpp @@ -207,4 +207,76 @@ namespace commandbuffers public: int error; }; + + class GetInternalformatParameterCommandBufferRequest final + : public TrCommandBufferSimpleRequest + { + public: + GetInternalformatParameterCommandBufferRequest() = delete; + GetInternalformatParameterCommandBufferRequest(uint32_t target, uint32_t internalformat, uint32_t pname) + : TrCommandBufferSimpleRequest() + , target(target) + , internalformat(internalformat) + , pname(pname) + { + } + GetInternalformatParameterCommandBufferRequest(const GetInternalformatParameterCommandBufferRequest &that, + bool clone = false) + : TrCommandBufferSimpleRequest(that, clone) + , target(that.target) + , internalformat(that.internalformat) + , pname(that.pname) + { + } + + public: + uint32_t target; + uint32_t internalformat; + uint32_t pname; + }; + + class GetInternalformatParameterCommandBufferResponse final + : public TrCommandBufferSimpleResponse + { + public: + GetInternalformatParameterCommandBufferResponse() = delete; + GetInternalformatParameterCommandBufferResponse(GetInternalformatParameterCommandBufferRequest *req, + const std::vector &values) + : TrCommandBufferSimpleResponse(COMMAND_BUFFER_GET_INTERNALFORMAT_PARAMETER_RES, req) + , values(values) + { + } + GetInternalformatParameterCommandBufferResponse(const GetInternalformatParameterCommandBufferResponse &that, + bool clone = false) + : TrCommandBufferSimpleResponse(that, clone) + { + if (clone) + values = that.values; + } + + public: + TrCommandBufferMessage *serialize() override + { + auto message = new TrCommandBufferMessage(type, size, this); + if (values.size() > 0) + { + // Serialize the vector using addVecSegment + message->addVecSegment(values); + } + return message; + } + + void deserialize(TrCommandBufferMessage &message) override + { + auto valuesSegment = message.nextSegment(); + if (valuesSegment != nullptr) + values = valuesSegment->toVec(); + else + values.clear(); + } + + public: + std::vector values; + }; } diff --git a/src/common/command_buffers/macros.hpp b/src/common/command_buffers/macros.hpp index 15bad43b4..07ed8094d 100644 --- a/src/common/command_buffers/macros.hpp +++ b/src/common/command_buffers/macros.hpp @@ -148,6 +148,7 @@ XX(SAMPLER_PARAMETERF, SamplerParameterfCommandBufferRequest, "GL::SamplerParameterf") \ XX(GET_SAMPLER_PARAMETER, GetSamplerParameterCommandBufferRequest, "GL::GetSamplerParameter") \ XX(IS_SAMPLER, IsSamplerCommandBufferRequest, "GL::IsSampler") \ + XX(GET_INTERNALFORMAT_PARAMETER, GetInternalformatParameterCommandBufferRequest, "GL::GetInternalformatParameter") \ XX(XRFRAME_START, XRFrameStartCommandBufferRequest, "XR::FrameStart") \ XX(XRFRAME_FLUSH, XRFrameFlushCommandBufferRequest, "XR::FrameFlush") \ XX(XRFRAME_END, XRFrameEndCommandBufferRequest, "XR::FrameEnd") \ @@ -171,4 +172,5 @@ XX(GET_FLOATV, GetFloatvCommandBufferResponse, "GL::GetFloatv") \ XX(GET_STRING, GetStringCommandBufferResponse, "GL::GetString") \ XX(GET_SHADER_PRECISION_FORMAT, GetShaderPrecisionFormatCommandBufferResponse, "GL::GetShaderPrecisionFormat") \ - XX(GET_ERROR, GetErrorCommandBufferResponse, "GL::GetError") + XX(GET_ERROR, GetErrorCommandBufferResponse, "GL::GetError") \ + XX(GET_INTERNALFORMAT_PARAMETER, GetInternalformatParameterCommandBufferResponse, "GL::GetInternalformatParameter") diff --git a/src/common/command_buffers/shared.hpp b/src/common/command_buffers/shared.hpp index a6a240567..9af627f16 100644 --- a/src/common/command_buffers/shared.hpp +++ b/src/common/command_buffers/shared.hpp @@ -233,6 +233,8 @@ namespace commandbuffers COMMAND_BUFFER_GET_SHADER_PRECISION_FORMAT_RES, COMMAND_BUFFER_GET_ERROR_REQ, COMMAND_BUFFER_GET_ERROR_RES, + COMMAND_BUFFER_GET_INTERNALFORMAT_PARAMETER_REQ, + COMMAND_BUFFER_GET_INTERNALFORMAT_PARAMETER_RES, /** XRFrame controls */ COMMAND_BUFFER_XRFRAME_START_REQ, diff --git a/src/common/command_buffers/webgl_constants.hpp b/src/common/command_buffers/webgl_constants.hpp index a2b30d1b5..2a8155c55 100644 --- a/src/common/command_buffers/webgl_constants.hpp +++ b/src/common/command_buffers/webgl_constants.hpp @@ -343,6 +343,7 @@ const int WEBGL_TEXTURE_BINDING_2D = 0x8069; const int WEBGL_SAMPLE_BUFFERS = 0x80A8; const int WEBGL_SAMPLES = 0x80A9; const int WEBGL_SAMPLE_COVERAGE_VALUE = 0x80AA; +const int GL_NUM_SAMPLE_COUNTS = 0x9380; const int WEBGL_SAMPLE_COVERAGE_INVERT = 0x80AB; const int WEBGL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; const int WEBGL_VENDOR = 0x1F00; diff --git a/src/renderer/render_api_opengles.cpp b/src/renderer/render_api_opengles.cpp index 5459a69e5..5242c2d53 100644 --- a/src/renderer/render_api_opengles.cpp +++ b/src/renderer/render_api_opengles.cpp @@ -2689,6 +2689,73 @@ class RHI_OpenGL : public TrRenderHardwareInterface DEBUG(DEBUG_TAG, "[%d] GL::GetError() => %d", options.isDefaultQueue(), res.error); reqContentRenderer->sendCommandBufferResponse(res); } + TR_OPENGL_FUNC void OnGetInternalformatParameter(GetInternalformatParameterCommandBufferRequest *req, + renderer::TrContentRenderer *reqContentRenderer, + ApiCallOptions &options) + { + std::vector values; + + // Support WEBGL_SAMPLES and GL_NUM_SAMPLE_COUNTS, log error for others + if (req->pname == WEBGL_SAMPLES) + { + GLint numSampleCounts = 0; + glGetInternalformativ(req->target, req->internalformat, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); + GLenum error = glGetError(); + if (error == GL_NO_ERROR && numSampleCounts > 0) + { + std::vector samples(numSampleCounts); + glGetInternalformativ(req->target, req->internalformat, GL_SAMPLES, numSampleCounts, samples.data()); + error = glGetError(); + + if (error == GL_NO_ERROR) + { + for (GLint sample : samples) + { + if (sample > 0) + values.push_back(static_cast(sample)); + } + std::sort(values.begin(), values.end(), std::greater()); + } + } + if (values.empty()) + { + DEBUG(DEBUG_TAG, "[GetInternalformatParameter] Using fallback values {4, 2, 1}"); + values = {4, 2, 1}; + } + } + else if (req->pname == GL_NUM_SAMPLE_COUNTS) + { + GLint numSampleCounts = 0; + glGetInternalformativ(req->target, req->internalformat, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + { + values.push_back(static_cast(numSampleCounts)); + } + } + else + { + // Not implemented for other pnames + DEBUG(LOG_TAG_ERROR, + "[GetInternalformatParameter] pname 0x%x is not supported.", + req->pname); + } + + GetInternalformatParameterCommandBufferResponse res(req, values); + // Note: CheckError is called here but won't detect errors from glGetInternalformativ + // calls above since those errors are already consumed by explicit glGetError() calls + if (TR_UNLIKELY(CheckError(req, reqContentRenderer) != GL_NO_ERROR || options.printsCall)) + { + DEBUG(DEBUG_TAG, + "[%d] GL::GetInternalformativ(0x%x, 0x%x, 0x%x) => [%zu values]", + options.isDefaultQueue(), + req->target, + req->internalformat, + req->pname, + values.size()); + } + reqContentRenderer->sendCommandBufferResponse(res); + } }; void RHI_OpenGL::ProcessDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces *interfaces) @@ -3026,6 +3093,9 @@ bool RHI_OpenGL::ExecuteCommandBuffer(vector