diff --git a/Libraries/LibWeb/WebGL/WebGL2RenderingContextImpl.cpp b/Libraries/LibWeb/WebGL/WebGL2RenderingContextImpl.cpp index 3cc094a114e..f04851eafa5 100644 --- a/Libraries/LibWeb/WebGL/WebGL2RenderingContextImpl.cpp +++ b/Libraries/LibWeb/WebGL/WebGL2RenderingContextImpl.cpp @@ -2849,6 +2849,8 @@ JS::Value WebGL2RenderingContextImpl::get_parameter(WebIDL::UnsignedLong pname) glGetBooleanvRobustANGLE(GL_TRANSFORM_FEEDBACK_PAUSED, 1, nullptr, &result); return JS::Value(result == GL_TRUE); } + case UNPACK_FLIP_Y_WEBGL: + return JS::Value(m_unpack_flip_y); default: dbgln("Unknown WebGL parameter name: {:x}", pname); set_error(GL_INVALID_ENUM); @@ -3145,6 +3147,13 @@ void WebGL2RenderingContextImpl::link_program(GC::Root program) void WebGL2RenderingContextImpl::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; + } + glPixelStorei(pname, param); } diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp index 1eca3c14e8f..046bd938583 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp @@ -12,6 +12,7 @@ extern "C" { #include } +#include #include #include #include @@ -20,10 +21,12 @@ extern "C" { #include #include +#include #include #include #include #include +#include namespace Web::WebGL { @@ -178,8 +181,20 @@ Optional WebGLRenderingContextBase: // FIXME: Respect unpackColorSpace auto color_space = SkColorSpace::MakeSRGB(); auto image_info = SkImageInfo::Make(width, height, skia_format, SkAlphaType::kPremul_SkAlphaType, color_space); - SkPixmap const pixmap(image_info, buffer.data(), buffer_pitch.value()); - bitmap->sk_image()->readPixels(pixmap, 0, 0); + auto surface = SkSurfaces::WrapPixels(image_info, buffer.data(), buffer_pitch.value()); + auto surface_canvas = surface->getCanvas(); + auto dst_rect = Gfx::to_skia_rect(Gfx::Rect { 0, 0, width, height }); + + // The first pixel transferred from the source to the WebGL implementation corresponds to the upper left corner of + // the source. This behavior is modified by the UNPACK_FLIP_Y_WEBGL pixel storage parameter, except for ImageBitmap + // arguments, as described in the abovementioned section. + if (m_unpack_flip_y && !source.has>()) { + surface_canvas->translate(0, dst_rect.height()); + surface_canvas->scale(1, -1); + } + + surface_canvas->drawImageRect(bitmap->sk_image(), dst_rect, Gfx::to_skia_sampling_options(Gfx::ScalingMode::NearestNeighbor)); + return ConvertedTexture { .buffer = move(buffer), .width = width, diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h index 1f1d045d2a6..6ece0ef8b02 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h @@ -14,6 +14,8 @@ namespace Web::WebGL { +static constexpr int UNPACK_FLIP_Y_WEBGL = 0x9240; + // NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly. using TexImageSource = Variant, GC::Root, GC::Root, GC::Root, GC::Root, GC::Root>; @@ -107,7 +109,14 @@ public: int width { 0 }; int height { 0 }; }; - static Optional read_and_pixel_convert_texture_image_source(TexImageSource const& source, WebIDL::UnsignedLong format, WebIDL::UnsignedLong type, Optional destination_width = OptionalNone {}, Optional destination_height = OptionalNone {}); + Optional read_and_pixel_convert_texture_image_source(TexImageSource const& source, WebIDL::UnsignedLong format, WebIDL::UnsignedLong type, Optional destination_width = OptionalNone {}, Optional destination_height = OptionalNone {}); + +protected: + // UNPACK_FLIP_Y_WEBGL of type boolean + // If set, then during any subsequent calls to texImage2D or texSubImage2D, the source data is flipped along + // the vertical axis, so that conceptually the last row is the first one transferred. The initial value is false. + // Any non-zero value is interpreted as true. + bool m_unpack_flip_y { false }; }; } diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextImpl.cpp b/Libraries/LibWeb/WebGL/WebGLRenderingContextImpl.cpp index c179c9ab307..3848ab26f87 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextImpl.cpp +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContextImpl.cpp @@ -1501,6 +1501,8 @@ JS::Value WebGLRenderingContextImpl::get_parameter(WebIDL::UnsignedLong pname) set_error(GL_INVALID_ENUM); return JS::js_null(); } + case UNPACK_FLIP_Y_WEBGL: + return JS::Value(m_unpack_flip_y); default: dbgln("Unknown WebGL parameter name: {:x}", pname); set_error(GL_INVALID_ENUM); @@ -1793,6 +1795,13 @@ void WebGLRenderingContextImpl::link_program(GC::Root program) 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; + } + glPixelStorei(pname, param); }