Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/Modules/WebGPU/GPUQueue.cpp
Warning:line 489, column 19
Local variable 'cachedImage' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource33.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource33.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/11721353671419897710/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I PAL -I ForwardingHeaders -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release-iphonesimulator/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource33.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource33.cpp
1/*
2 * Copyright (C) 2021-2023 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "GPUQueue.h"
28
29#include "BitmapImage.h"
30#include "CachedImage.h"
31#include "CanvasRenderingContext.h"
32#include "GPUBuffer.h"
33#include "GPUDevice.h"
34#include "GPUImageCopyExternalImage.h"
35#include "GPUTexture.h"
36#include "GPUTextureDescriptor.h"
37#include "HTMLImageElement.h"
38#include "HTMLVideoElement.h"
39#include "ImageBuffer.h"
40#include "ImageData.h"
41#include "JSDOMPromiseDeferred.h"
42#include "OffscreenCanvas.h"
43#include "PixelBuffer.h"
44#include "SVGImage.h"
45#include "SecurityOrigin.h"
46#include "VideoFrame.h"
47#include "WebCodecsVideoFrame.h"
48#include "WebGPUDevice.h"
49#include <wtf/CheckedArithmetic.h>
50#include <wtf/MallocSpan.h>
51
52#if PLATFORM(COCOA)(defined 1 && 1)
53#include <Accelerate/Accelerate.h>
54#include <wtf/cf/VectorCF.h>
55
56#include "CoreVideoSoftLink.h"
57#endif
58
59namespace WebCore {
60
61GPUQueue::GPUQueue(Ref<WebGPU::Queue>&& backing, WebGPU::Device& device)
62 : m_backing(WTF::move(backing))
63 , m_device(&device)
64{
65}
66
67String GPUQueue::label() const
68{
69 return m_backing->label();
70}
71
72void GPUQueue::setLabel(String&& label)
73{
74 m_backing->setLabel(WTF::move(label));
75}
76
77void GPUQueue::submit(Vector<Ref<GPUCommandBuffer>>&& commandBuffers)
78{
79 auto result = WTF::map(commandBuffers, [](auto& commandBuffer) -> Ref<WebGPU::CommandBuffer> {
80 return commandBuffer->backing();
81 });
82 m_backing->submit(WTF::move(result));
83
84 if (RefPtr device = m_device.get()) {
85 for (Ref commandBuffer : commandBuffers) {
86 commandBuffer->setOverrideLabel(commandBuffer->label());
87 commandBuffer->setBacking(device->invalidCommandEncoder(), device->invalidCommandBuffer());
88 }
89 }
90}
91
92void GPUQueue::onSubmittedWorkDone(OnSubmittedWorkDonePromise&& promise)
93{
94 m_backing->onSubmittedWorkDone([promise = WTF::move(promise)]() mutable {
95 promise.resolve(nullptr);
96 });
97}
98
99static GPUSize64 computeElementSize(const BufferSource& data)
100{
101 return WTF::switchOn(data.variant(),
102 [&](const Ref<JSC::ArrayBufferView>& bufferView) {
103 return static_cast<GPUSize64>(JSC::elementSize(bufferView->getType()));
104 },
105 [&](const Ref<JSC::ArrayBuffer>&) {
106 return static_cast<GPUSize64>(1);
107 }
108 );
109}
110
111ExceptionOr<void> GPUQueue::writeBuffer(
112 const GPUBuffer& buffer,
113 GPUSize64 bufferOffset,
114 BufferSource&& data,
115 GPUSize64 optionalDataOffset,
116 std::optional<GPUSize64> optionalSize)
117{
118 auto elementSize = computeElementSize(data);
119 auto dataOffset = elementSize * optionalDataOffset;
120 auto dataSize = data.byteLength();
121 auto contentSize = optionalSize.has_value() ? (elementSize * optionalSize.value()) : (dataSize - dataOffset);
122
123 if (dataOffset > dataSize || dataOffset + contentSize > dataSize || (contentSize % 4))
124 return Exception { ExceptionCode::OperationError };
125
126 m_backing->writeBuffer(buffer.backing(), bufferOffset, data.span().subspan(dataOffset, contentSize), 0, contentSize);
127 return { };
128}
129
130static uint32_t getExtentDimension(const GPUExtent3D& size, size_t dimension)
131{
132 return WTF::switchOn(size, [&](const Vector<GPUIntegerCoordinate>& v) -> uint32_t {
133 return dimension < v.size() ? v[dimension] : 0u;
134 }, [&](const GPUExtent3DDict& size) -> uint32_t {
135 switch (dimension) {
136 default:
137 case 0:
138 return size.width;
139 case 1:
140 return size.height;
141 case 2:
142 return size.depthOrArrayLayers;
143 }
144 });
145}
146
147static uint32_t width(const GPUExtent3D& extent)
148{
149 return getExtentDimension(extent, 0);
150}
151static uint32_t height(const GPUExtent3D& extent)
152{
153 return getExtentDimension(extent, 1);
154}
155static uint32_t depth(const GPUExtent3D& extent)
156{
157 return getExtentDimension(extent, 2);
158}
159
160static size_t requiredBytesInCopy(const GPUImageCopyTexture& destination, const GPUImageDataLayout& layout, const GPUExtent3D& copyExtent)
161{
162 using namespace WebGPU;
163
164 Ref texture = destination.texture;
165
166 auto aspectSpecificFormat = GPUTexture::aspectSpecificFormat(texture->format(), destination.aspect);
167 uint32_t blockWidth = GPUTexture::texelBlockWidth(aspectSpecificFormat);
168 uint32_t blockHeight = GPUTexture::texelBlockHeight(aspectSpecificFormat);
169 uint32_t blockSize = GPUTexture::texelBlockSize(aspectSpecificFormat);
170
171 auto copyExtentWidth = width(copyExtent);
172 auto widthInBlocks = copyExtentWidth / blockWidth;
173 if (copyExtentWidth % blockWidth)
174 return 0;
175
176 auto copyExtentHeight = height(copyExtent);
177 auto heightInBlocks = copyExtentHeight / blockHeight;
178 if (copyExtentHeight % blockHeight)
179 return 0;
180
181 auto bytesInLastRow = checkedProduct<uint64_t>(blockSize, widthInBlocks);
182 if (bytesInLastRow.hasOverflowed())
183 return 0;
184
185 auto requiredBytesInCopy = CheckedUint64(bytesInLastRow);
186 auto bytesPerImage = CheckedUint64(0);
187 if (heightInBlocks > 1) {
188 if (!layout.bytesPerRow.has_value())
189 return 0;
190
191 bytesPerImage = layout.bytesPerRow.value() * heightInBlocks;
192 requiredBytesInCopy = bytesPerImage;
193 }
194
195 auto copyExtentDepthOrArrayLayers = depth(copyExtent);
196 if (copyExtentDepthOrArrayLayers > 1) {
197 if (!layout.bytesPerRow.has_value() || !layout.rowsPerImage.has_value())
198 return 0;
199 }
200
201 if (layout.bytesPerRow.has_value()) {
202 if (*layout.bytesPerRow < bytesInLastRow.value())
203 return 0;
204 }
205
206 if (layout.rowsPerImage.has_value()) {
207 if (layout.rowsPerImage < heightInBlocks)
208 return 0;
209 }
210
211 if (copyExtentDepthOrArrayLayers > 0) {
212 requiredBytesInCopy = CheckedUint64(0);
213
214 if (heightInBlocks > 1)
215 requiredBytesInCopy += checkedProduct<uint64_t>(*layout.bytesPerRow, checkedDifference<uint64_t>(heightInBlocks, 1));
216
217 if (heightInBlocks > 0)
218 requiredBytesInCopy += bytesInLastRow;
219
220 if (copyExtentDepthOrArrayLayers > 1) {
221 bytesPerImage = checkedProduct<uint64_t>(*layout.bytesPerRow, *layout.rowsPerImage);
222
223 auto bytesBeforeLastImage = checkedProduct<uint64_t>(bytesPerImage, checkedDifference<uint64_t>(copyExtentDepthOrArrayLayers, 1));
224 requiredBytesInCopy += bytesBeforeLastImage;
225 }
226 }
227
228 return requiredBytesInCopy.hasOverflowed() ? 0 : requiredBytesInCopy.value();
229}
230
231void GPUQueue::writeTexture(
232 const GPUImageCopyTexture& destination,
233 BufferSource&& data,
234 const GPUImageDataLayout& initialImageDataLayout,
235 const GPUExtent3D& size)
236{
237 auto imageDataLayout = initialImageDataLayout;
238 auto initialOffset = imageDataLayout.offset;
239 auto span = data.span();
240 auto spanLength = span.size();
241 auto requiredBytes = requiredBytesInCopy(destination, imageDataLayout, size);
242 if (initialOffset >= spanLength) {
243 initialOffset = 0;
244 requiredBytes = spanLength;
245 } else {
246 imageDataLayout.offset = 0;
247 requiredBytes = std::min<size_t>(spanLength - initialOffset, requiredBytes);
248 }
249
250 m_backing->writeTexture(destination.convertToBacking(), span.subspan(initialOffset, requiredBytes), imageDataLayout.convertToBacking(), convertToBacking(size));
251}
252
253#if PLATFORM(COCOA)(defined 1 && 1) && ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
254static PixelFormat NODELETE[[clang::annotate_type("webkit.nodelete")]] toPixelFormat(GPUTextureFormat textureFormat)
255{
256 switch (textureFormat) {
257 case GPUTextureFormat::R8unorm:
258 case GPUTextureFormat::R8snorm:
259 case GPUTextureFormat::R8uint:
260 case GPUTextureFormat::R8sint:
261 case GPUTextureFormat::R16unorm:
262 case GPUTextureFormat::R16snorm:
263 case GPUTextureFormat::R16uint:
264 case GPUTextureFormat::R16sint:
265 case GPUTextureFormat::R16float:
266 case GPUTextureFormat::Rg8unorm:
267 case GPUTextureFormat::Rg8snorm:
268 case GPUTextureFormat::Rg8uint:
269 case GPUTextureFormat::Rg8sint:
270 case GPUTextureFormat::R32uint:
271 case GPUTextureFormat::R32sint:
272 case GPUTextureFormat::R32float:
273 case GPUTextureFormat::Rg16unorm:
274 case GPUTextureFormat::Rg16snorm:
275 case GPUTextureFormat::Rg16uint:
276 case GPUTextureFormat::Rg16sint:
277 case GPUTextureFormat::Rg16float:
278 case GPUTextureFormat::Rgba8unorm:
279 case GPUTextureFormat::Rgba8unormSRGB:
280 case GPUTextureFormat::Rgba8snorm:
281 case GPUTextureFormat::Rgba8uint:
282 case GPUTextureFormat::Rgba8sint:
283 return PixelFormat::RGBA8;
284
285 case GPUTextureFormat::Bgra8unorm:
286 case GPUTextureFormat::Bgra8unormSRGB:
287 return PixelFormat::BGRA8;
288
289 case GPUTextureFormat::Rgb9e5ufloat:
290 case GPUTextureFormat::Rgb10a2uint:
291 case GPUTextureFormat::Rgb10a2unorm:
292 case GPUTextureFormat::Rg11b10ufloat:
293 case GPUTextureFormat::Rg32uint:
294 case GPUTextureFormat::Rg32sint:
295 case GPUTextureFormat::Rg32float:
296 case GPUTextureFormat::Rgba16unorm:
297 case GPUTextureFormat::Rgba16snorm:
298 case GPUTextureFormat::Rgba16uint:
299 case GPUTextureFormat::Rgba16sint:
300 case GPUTextureFormat::Rgba16float:
301 case GPUTextureFormat::Rgba32uint:
302 case GPUTextureFormat::Rgba32sint:
303 case GPUTextureFormat::Rgba32float:
304 case GPUTextureFormat::Stencil8:
305 case GPUTextureFormat::Depth16unorm:
306 case GPUTextureFormat::Depth24plus:
307 case GPUTextureFormat::Depth24plusStencil8:
308 case GPUTextureFormat::Depth32float:
309 case GPUTextureFormat::Depth32floatStencil8:
310 case GPUTextureFormat::Bc1RgbaUnorm:
311 case GPUTextureFormat::Bc1RgbaUnormSRGB:
312 case GPUTextureFormat::Bc2RgbaUnorm:
313 case GPUTextureFormat::Bc2RgbaUnormSRGB:
314 case GPUTextureFormat::Bc3RgbaUnorm:
315 case GPUTextureFormat::Bc3RgbaUnormSRGB:
316 case GPUTextureFormat::Bc4RUnorm:
317 case GPUTextureFormat::Bc4RSnorm:
318 case GPUTextureFormat::Bc5RgUnorm:
319 case GPUTextureFormat::Bc5RgSnorm:
320 case GPUTextureFormat::Bc6hRgbUfloat:
321 case GPUTextureFormat::Bc6hRgbFloat:
322 case GPUTextureFormat::Bc7RgbaUnorm:
323 case GPUTextureFormat::Bc7RgbaUnormSRGB:
324 case GPUTextureFormat::Etc2Rgb8unorm:
325 case GPUTextureFormat::Etc2Rgb8unormSRGB:
326 case GPUTextureFormat::Etc2Rgb8a1unorm:
327 case GPUTextureFormat::Etc2Rgb8a1unormSRGB:
328 case GPUTextureFormat::Etc2Rgba8unorm:
329 case GPUTextureFormat::Etc2Rgba8unormSRGB:
330 case GPUTextureFormat::EacR11unorm:
331 case GPUTextureFormat::EacR11snorm:
332 case GPUTextureFormat::EacRg11unorm:
333 case GPUTextureFormat::EacRg11snorm:
334 case GPUTextureFormat::Astc4x4Unorm:
335 case GPUTextureFormat::Astc4x4UnormSRGB:
336 case GPUTextureFormat::Astc5x4Unorm:
337 case GPUTextureFormat::Astc5x4UnormSRGB:
338 case GPUTextureFormat::Astc5x5Unorm:
339 case GPUTextureFormat::Astc5x5UnormSRGB:
340 case GPUTextureFormat::Astc6x5Unorm:
341 case GPUTextureFormat::Astc6x5UnormSRGB:
342 case GPUTextureFormat::Astc6x6Unorm:
343 case GPUTextureFormat::Astc6x6UnormSRGB:
344 case GPUTextureFormat::Astc8x5Unorm:
345 case GPUTextureFormat::Astc8x5UnormSRGB:
346 case GPUTextureFormat::Astc8x6Unorm:
347 case GPUTextureFormat::Astc8x6UnormSRGB:
348 case GPUTextureFormat::Astc8x8Unorm:
349 case GPUTextureFormat::Astc8x8UnormSRGB:
350 case GPUTextureFormat::Astc10x5Unorm:
351 case GPUTextureFormat::Astc10x5UnormSRGB:
352 case GPUTextureFormat::Astc10x6Unorm:
353 case GPUTextureFormat::Astc10x6UnormSRGB:
354 case GPUTextureFormat::Astc10x8Unorm:
355 case GPUTextureFormat::Astc10x8UnormSRGB:
356 case GPUTextureFormat::Astc10x10Unorm:
357 case GPUTextureFormat::Astc10x10UnormSRGB:
358 case GPUTextureFormat::Astc12x10Unorm:
359 case GPUTextureFormat::Astc12x10UnormSRGB:
360 case GPUTextureFormat::Astc12x12Unorm:
361 case GPUTextureFormat::Astc12x12UnormSRGB:
362 return PixelFormat::RGBA8;
363 }
364
365 return PixelFormat::RGBA8;
366}
367#endif
368
369using ImageDataCallback = Function<void(std::span<const uint8_t>, size_t, size_t)>;
370static void getImageBytesFromImageBuffer(const RefPtr<ImageBuffer>& imageBuffer, bool& needsPremultipliedAlpha, NOESCAPE[[clang::noescape]] const ImageDataCallback& callback)
371{
372 UNUSED_PARAM(needsPremultipliedAlpha)(void)needsPremultipliedAlpha;
373 if (!imageBuffer)
374 return callback({ }, 0, 0);
375
376 auto size = imageBuffer->truncatedLogicalSize();
377 if (!size.width() || !size.height())
378 return callback({ }, 0, 0);
379
380 auto pixelBuffer = imageBuffer->getPixelBuffer({ AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB() }, { { }, size });
381 if (!pixelBuffer)
382 return callback({ }, 0, 0);
383
384 callback(pixelBuffer->bytes(), size.width(), size.height());
385}
386
387#if PLATFORM(COCOA)(defined 1 && 1) && ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
388static void clampDimension(WebGPU::Extent3D& extent3D, size_t dimension, WebGPU::IntegerCoordinate minValue)
389{
390 return WTF::switchOn(extent3D, [&](Vector<WebGPU::IntegerCoordinate>& vector) {
391 if (dimension < vector.size())
392 vector[dimension] = std::min<WebGPU::IntegerCoordinate>(minValue, vector[dimension]);
393 }, [&](WebGPU::Extent3DDict& extent3D) {
394 switch (dimension) {
395 case 0:
396 extent3D.width = std::min<WebGPU::IntegerCoordinate>(minValue, extent3D.width);
397 break;
398 case 1:
399 extent3D.height = std::min<WebGPU::IntegerCoordinate>(minValue, extent3D.height);
400 break;
401 case 2:
402 extent3D.depthOrArrayLayers = std::min<WebGPU::IntegerCoordinate>(minValue, extent3D.depthOrArrayLayers);
403 break;
404 default:
405 ASSERT_NOT_REACHED()((void)0);
406 break;
407 }
408 });
409}
410
411static void getImageBytesFromVideoFrame(WebGPU::Queue& backing, const RefPtr<VideoFrame>& videoFrame, WebGPU::Extent3D& backingCopySize, NOESCAPE[[clang::noescape]] const ImageDataCallback& callback)
412{
413 if (!videoFrame.get())
414 return callback({ }, 0, 0);
415
416 RefPtr<NativeImage> nativeImage = backing.getNativeImage(*videoFrame.get());
417 if (!nativeImage)
418 return callback({ }, 0, 0);
419
420 RetainPtr platformImage = nativeImage->platformImage();
421 if (!platformImage)
422 return callback({ }, 0, 0);
423 RetainPtr pixelDataCfData = adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(platformImage.get())));
424 if (!pixelDataCfData)
425 return callback({ }, 0, 0);
426
427 auto width = CGImageGetWidth(platformImage.get());
428 auto height = CGImageGetHeight(platformImage.get());
429 if (!width || !height)
430 return callback({ }, 0, 0);
431
432 clampDimension(backingCopySize, 0, width);
433 clampDimension(backingCopySize, 1, height);
434
435 auto sizeInBytes = height * CGImageGetBytesPerRow(platformImage.get());
436 auto byteSpan = span(pixelDataCfData.get());
437 vImage_Buffer bgra {
438 .data = const_cast<unsigned char*>(&byteSpan[0]),
439 .height = height,
440 .width = width,
441 .rowBytes = byteSpan.size() / height
442 };
443 uint8_t permuteMap[4] = { 2, 1, 0, 3 };
444 vImagePermuteChannels_ARGB8888(&bgra, &bgra, permuteMap, kvImageNoFlags);
445
446 return callback(byteSpan.first(sizeInBytes), width, height);
447}
448#endif
449
450#if PLATFORM(COCOA)(defined 1 && 1) && ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
451static void clipTo8bitsPerChannel(std::span<const uint8_t> data, size_t bitsPerComponent, Vector<uint8_t>& byteSpanBacking)
452{
453 RELEASE_ASSERT(bitsPerComponent != 8)do { if (__builtin_expect(!!(!(bitsPerComponent != 8)), 0)) do
{ WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(453, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/Modules/WebGPU/GPUQueue.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
454
455 if (bitsPerComponent == 16) {
456 byteSpanBacking.resize(data.size() / 2);
457 auto uint16Span = unsafeMakeSpan(static_cast<const uint16_t*>(static_cast<const void*>(data.data())), byteSpanBacking.size());
458 for (size_t i = 0; i < uint16Span.size(); ++i)
459 byteSpanBacking[i] = std::min<uint8_t>(255, uint16Span[i]);
460 } else if (bitsPerComponent == 32) {
461 byteSpanBacking.resize(data.size() / 4);
462 auto uint32Span = unsafeMakeSpan(static_cast<const uint32_t*>(static_cast<const void*>(data.data())), byteSpanBacking.size());
463 for (size_t i = 0; i < uint32Span.size(); ++i)
464 byteSpanBacking[i] = std::min<uint8_t>(255, uint32Span[i]);
465 }
466}
467#endif
468
469static void imageBytesForSource(WebGPU::Queue& backing, const GPUImageCopyExternalImage& sourceDescriptor, const GPUImageCopyTextureTagged& destination, bool& needsYFlip, bool& needsPremultipliedAlpha, WebGPU::Extent3D& backingCopySize, NOESCAPE[[clang::noescape]] const ImageDataCallback& callback)
470{
471 UNUSED_PARAM(needsYFlip)(void)needsYFlip;
472 UNUSED_PARAM(needsPremultipliedAlpha)(void)needsPremultipliedAlpha;
473 UNUSED_PARAM(backing)(void)backing;
474 UNUSED_PARAM(backingCopySize)(void)backingCopySize;
475 UNUSED_PARAM(destination)(void)destination;
476
477 const auto& source = sourceDescriptor.source;
478 using ResultType = void;
479 return WTF::switchOn(source,
480 [&](const Ref<ImageBitmap>& imageBitmap) -> ResultType {
481 return getImageBytesFromImageBuffer(imageBitmap->buffer(), needsPremultipliedAlpha, callback);
482 },
483#if ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
484 [&](const Ref<ImageData>& imageData) -> ResultType {
485 callback(imageData->byteArrayPixelBuffer()->bytes(), imageData->width(), imageData->height());
486 },
487 [&]([[maybe_unused]] const Ref<HTMLImageElement>& imageElement) -> ResultType {
488#if PLATFORM(COCOA)(defined 1 && 1)
489 auto* cachedImage = imageElement->cachedImage();
Local variable 'cachedImage' is uncounted and unsafe
490 if (!cachedImage)
491 return callback({ }, 0, 0);
492 RefPtr image = dynamicDowncast<BitmapImage>(cachedImage->image());
493 RefPtr<NativeImage> nativeImage;
494 bool isSVG = false;
495 if (image)
496 nativeImage = image->nativeImage();
497 else {
498 RefPtr svgImage = dynamicDowncast<SVGImage>(cachedImage->image());
499 RefPtr texturePtr = destination.texture.get();
500 if (texturePtr) {
501 nativeImage = svgImage->nativeImage(FloatSize(texturePtr->width(), texturePtr->height()));
502 isSVG = true;
503 }
504 }
505
506 if (!nativeImage)
507 return callback({ }, 0, 0);
508 RetainPtr platformImage = nativeImage->platformImage();
509 if (!platformImage)
510 return callback({ }, 0, 0);
511 RetainPtr pixelDataCfData = adoptCF(CGDataProviderCopyData(RetainPtr { CGImageGetDataProvider(platformImage.get()) }.get()));
512 if (!pixelDataCfData)
513 return callback({ }, 0, 0);
514
515 auto rawWidth = CGImageGetWidth(platformImage.get());
516 auto rawHeight = CGImageGetHeight(platformImage.get());
517 auto orientedWidth = isSVG ? rawWidth : imageElement->width();
518 auto orientedHeight = isSVG ? rawHeight : imageElement->height();
519
520 if (!orientedWidth || !orientedHeight || !rawWidth || !rawHeight)
521 return callback({ }, 0, 0);
522
523 auto sizeInBytes = rawHeight * CGImageGetBytesPerRow(platformImage.get());
524 auto bitsPerComponent = CGImageGetBitsPerComponent(platformImage.get());
525 auto byteSpan = span(pixelDataCfData.get());
526 Vector<uint8_t> byteSpanBacking;
527 if (bitsPerComponent != 8) {
528 clipTo8bitsPerChannel(byteSpan, bitsPerComponent, byteSpanBacking);
529 byteSpan = byteSpanBacking.span();
530 sizeInBytes = byteSpan.size();
531 }
532
533 auto requiredSize = orientedWidth * orientedHeight * 4;
534 auto alphaInfo = CGImageGetAlphaInfo(platformImage.get());
535 bool channelLayoutIsRGB = false;
536 bool isBGRA = toPixelFormat(destination.texture->format()) == PixelFormat::BGRA8;
537 bool hasAlpha = false;
538 static constexpr std::array channelsSVG1 { 0, 1, 2, 3 };
539 static constexpr std::array channelsSVG2 { 2, 1, 0, 3 };
540 static constexpr std::array channelsRGBX { 0, 1, 2, 3 };
541 static constexpr std::array channelsBGRX { 2, 1, 0, 3 };
542 static constexpr std::array channelsXRGB { 3, 0, 1, 2 };
543 static constexpr std::array channelsXBGR { 3, 2, 1, 0 };
544 auto& channels = [&] -> const std::array<int, 4>& {
545 if (isSVG)
546 return isBGRA ? channelsSVG1 : channelsSVG2;
547
548 switch (alphaInfo) {
549 case kCGImageAlphaPremultipliedLast: /* For example, premultiplied RGBA */
550 case kCGImageAlphaLast: /* For example, non-premultiplied RGBA */
551 hasAlpha = true;
552 [[fallthrough]];
553 case kCGImageAlphaNone: /* For example, RGB. */
554 case kCGImageAlphaNoneSkipLast: { /* For example, RGBX. */
555 channelLayoutIsRGB = true;
556 return isBGRA ? channelsBGRX : channelsRGBX;
557 }
558 case kCGImageAlphaPremultipliedFirst: /* For example, premultiplied ARGB */
559 case kCGImageAlphaFirst: /* For example, non-premultiplied ARGB */
560 case kCGImageAlphaOnly: /* No color data, alpha data only */
561 hasAlpha = true;
562 [[fallthrough]];
563 case kCGImageAlphaNoneSkipFirst: { /* For example, XRGB. */
564 return isBGRA ? channelsXBGR : channelsXRGB;
565 }
566 }
567 }();
568
569 auto orientation = RefPtr { imageElement->image() }->orientation().orientation();
570 if (sizeInBytes == requiredSize && channelLayoutIsRGB && orientation == ImageOrientation::Orientation::OriginTopLeft)
571 return callback(byteSpan.first(sizeInBytes), rawWidth, rawHeight);
572
573 auto bytesPerRow = CGImageGetBytesPerRow(platformImage.get()) / (bitsPerComponent / 8);
574 Vector<uint8_t> tempBuffer(requiredSize, 255);
575 auto bytesPerPixel = sizeInBytes / (rawWidth * rawHeight);
576 bool flipY = sourceDescriptor.flipY;
577 needsYFlip = false;
578 int direction = flipY ? -1 : 1;
579 auto maxChannelIndex = bytesPerPixel - 1;
580 auto alphaIndex = 0;
581 if (hasAlpha && maxChannelIndex > 0) {
582 --maxChannelIndex;
583 alphaIndex = 1;
584 }
585
586 auto mapDestinationToSource = [&orientation, &rawWidth, &rawHeight](size_t x, size_t y) -> std::pair<size_t, size_t> {
587 switch (orientation) {
588 case ImageOrientation::Orientation::OriginTopRight:
589 return { rawWidth - 1 - x, y };
590 case ImageOrientation::Orientation::OriginBottomRight:
591 return { rawWidth - 1 - x, rawHeight - 1 - y };
592 case ImageOrientation::Orientation::OriginBottomLeft:
593 return { x, rawHeight - 1 - y };
594 case ImageOrientation::Orientation::OriginLeftTop:
595 return { y, x };
596 case ImageOrientation::Orientation::OriginRightTop:
597 return { y, rawHeight - 1 - x };
598 case ImageOrientation::Orientation::OriginRightBottom:
599 return { rawWidth - 1 - y, rawHeight - 1 - x };
600 case ImageOrientation::Orientation::OriginLeftBottom:
601 return { rawWidth - 1 - y, x };
602 default:
603 return { x, y };
604 }
605 };
606
607 for (size_t y = 0, y0 = flipY ? (orientedHeight - 1) : 0; y < orientedHeight; ++y, y0 += direction) {
608 for (size_t x = 0; x < orientedWidth; ++x) {
609 auto [sourceX, sourceY] = mapDestinationToSource(x, y);
610
611 for (size_t c = 0; c < 4; ++c) {
612 if (channels[c] == 3 && bytesPerPixel < 4)
613 tempBuffer[y0 * (orientedWidth * 4) + x * 4 + channels[c]] = hasAlpha ? byteSpan[sourceY * bytesPerRow + sourceX * bytesPerPixel + alphaIndex] : 255;
614 else
615 tempBuffer[y0 * (orientedWidth * 4) + x * 4 + channels[c]] = byteSpan[sourceY * bytesPerRow + sourceX * bytesPerPixel + std::min<size_t>(maxChannelIndex, c)];
616 }
617 }
618 }
619 callback(tempBuffer.span(), orientedWidth, orientedHeight);
620#else
621 return callback({ }, 0, 0);
622#endif
623 },
624 [&]([[maybe_unused]] const Ref<HTMLVideoElement>& videoElement) -> ResultType {
625#if PLATFORM(COCOA)(defined 1 && 1)
626 if (RefPtr player = videoElement->player(); player && player->isVideoPlayer())
627 return getImageBytesFromVideoFrame(backing, player->videoFrameForCurrentTime(), backingCopySize, callback);
628#endif
629 return callback({ }, 0, 0);
630 },
631 [&]([[maybe_unused]] const Ref<WebCodecsVideoFrame>& webCodecsFrame) -> ResultType {
632#if PLATFORM(COCOA)(defined 1 && 1)
633 return getImageBytesFromVideoFrame(backing, webCodecsFrame->internalFrame(), backingCopySize, callback);
634#else
635 return callback({ }, 0, 0);
636#endif
637 },
638#endif
639 [&](const Ref<HTMLCanvasElement>& canvasElement) -> ResultType {
640 return getImageBytesFromImageBuffer(canvasElement->makeRenderingResultsAvailable(ShouldApplyPostProcessingToDirtyRect::No), needsPremultipliedAlpha, callback);
641 }
642#if ENABLE(OFFSCREEN_CANVAS)(defined 1 && 1)
643 , [&](const Ref<OffscreenCanvas>& offscreenCanvasElement) -> ResultType {
644 return getImageBytesFromImageBuffer(offscreenCanvasElement->makeRenderingResultsAvailable(ShouldApplyPostProcessingToDirtyRect::No), needsPremultipliedAlpha, callback);
645 }
646#endif
647 );
648}
649
650static bool isOriginClean(const auto& source, [[maybe_unused]] ScriptExecutionContext& context)
651{
652 using ResultType = bool;
653 return WTF::switchOn(source,
654 [&](const Ref<ImageBitmap>& imageBitmap) -> ResultType {
655 return imageBitmap->originClean();
656 },
657#if ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
658 [&](const Ref<ImageData>&) -> ResultType {
659 return true;
660 },
661 [&](const Ref<HTMLImageElement>& imageElement) -> ResultType {
662 return imageElement->originClean(*protect(context.securityOrigin()).get());
663 },
664 [&]([[maybe_unused]] const Ref<HTMLVideoElement>& videoElement) -> ResultType {
665#if PLATFORM(COCOA)(defined 1 && 1)
666 return !videoElement->taintsOrigin(*protect(context.securityOrigin()).get());
667#else
668 return true;
669#endif
670 },
671 [&](const Ref<WebCodecsVideoFrame>&) -> ResultType {
672 return true;
673 },
674#endif
675 [&](const Ref<HTMLCanvasElement>& canvasElement) -> ResultType {
676 return canvasElement->originClean();
677 }
678#if ENABLE(OFFSCREEN_CANVAS)(defined 1 && 1)
679 , [&](const Ref<OffscreenCanvas>& offscreenCanvasElement) -> ResultType {
680 return offscreenCanvasElement->originClean();
681 }
682#endif
683 );
684}
685
686static GPUIntegerCoordinate dimension(const GPUExtent3D& extent3D, size_t dimension)
687{
688 return WTF::switchOn(extent3D, [&](const Vector<GPUIntegerCoordinate>& vector) -> GPUIntegerCoordinate {
689 return dimension < vector.size() ? vector[dimension] : 0;
690 }, [&](const GPUExtent3DDict& extent3D) -> GPUIntegerCoordinate {
691 switch (dimension) {
692 case 0:
693 return extent3D.width;
694 case 1:
695 return extent3D.height;
696 case 2:
697 return extent3D.depthOrArrayLayers;
698 default:
699 ASSERT_NOT_REACHED()((void)0);
700 return 0;
701 }
702 });
703}
704
705static GPUIntegerCoordinate dimension(const GPUOrigin2D& origin, size_t dimension)
706{
707 return WTF::switchOn(origin, [&](const Vector<GPUIntegerCoordinate>& vector) -> GPUIntegerCoordinate {
708 return dimension < vector.size() ? vector[dimension] : 0;
709 }, [&](const GPUOrigin2DDict& origin2D) -> GPUIntegerCoordinate {
710 switch (dimension) {
711 case 0:
712 return origin2D.x;
713 case 1:
714 return origin2D.y;
715 default:
716 ASSERT_NOT_REACHED()((void)0);
717 return 0;
718 }
719 });
720}
721
722static bool isStateValid(const auto& source, const std::optional<GPUOrigin2D>& origin, const GPUExtent3D& copySize, ExceptionCode& errorCode)
723{
724 using ResultType = bool;
725 auto checkedHorizontalDimension = checkedSum<uint32_t>((origin ? dimension(*origin, 0) : 0), dimension(copySize, 0));
726 auto checkedVerticalDimension = checkedSum<uint32_t>((origin ? dimension(*origin, 1) : 0), dimension(copySize, 1));
727 auto depthDimension = dimension(copySize, 2);
728 if (depthDimension > 1 || checkedHorizontalDimension.hasOverflowed() || checkedVerticalDimension.hasOverflowed()) {
729 errorCode = ExceptionCode::OperationError;
730 return false;
731 }
732
733 uint32_t horizontalDimension = checkedHorizontalDimension.value();
734 uint32_t verticalDimension = checkedVerticalDimension.value();
735
736 return WTF::switchOn(source,
737 [&](const Ref<ImageBitmap>& imageBitmap) -> ResultType {
738 if (!imageBitmap->buffer()) {
739 errorCode = ExceptionCode::InvalidStateError;
740 return false;
741 }
742 if (horizontalDimension > imageBitmap->width() || verticalDimension > imageBitmap->height()) {
743 errorCode = ExceptionCode::OperationError;
744 return false;
745 }
746 return true;
747 },
748#if ENABLE(VIDEO)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
749 [&](const Ref<ImageData>& imageData) -> ResultType {
750 auto width = imageData->width();
751 auto height = imageData->height();
752 if (width < 0 || height < 0 || horizontalDimension > static_cast<uint32_t>(width) || verticalDimension > static_cast<uint32_t>(height)) {
753 errorCode = ExceptionCode::OperationError;
754 return false;
755 }
756 auto size = width * height;
757 if (!size) {
758 errorCode = ExceptionCode::InvalidStateError;
759 return false;
760 }
761 return true;
762 },
763 [&](const Ref<HTMLImageElement>& imageElement) -> ResultType {
764 if (!imageElement->cachedImage()) {
765 errorCode = ExceptionCode::InvalidStateError;
766 return false;
767 }
768 if (horizontalDimension > imageElement->width() || verticalDimension > imageElement->height()) {
769 errorCode = ExceptionCode::OperationError;
770 return false;
771 }
772 return true;
773 },
774 [&](const Ref<HTMLVideoElement>&) -> ResultType {
775 return true;
776 },
777 [&](const Ref<WebCodecsVideoFrame>&) -> ResultType {
778 return true;
779 },
780#endif
781 [&](const Ref<HTMLCanvasElement>& canvas) -> ResultType {
782 if (!canvas->renderingContext()) {
783 errorCode = ExceptionCode::OperationError;
784 return false;
785 }
786 if (canvas->renderingContext()->isPlaceholder()) {
787 errorCode = ExceptionCode::InvalidStateError;
788 return false;
789 }
790 if (horizontalDimension > canvas->width() || verticalDimension > canvas->height()) {
791 errorCode = ExceptionCode::OperationError;
792 return false;
793 }
794 return true;
795 }
796#if ENABLE(OFFSCREEN_CANVAS)(defined 1 && 1)
797 , [&](const Ref<OffscreenCanvas>& offscreenCanvas) -> ResultType {
798 if (offscreenCanvas->isDetached()) {
799 errorCode = ExceptionCode::InvalidStateError;
800 return false;
801 }
802 if (!offscreenCanvas->renderingContext()) {
803 errorCode = ExceptionCode::OperationError;
804 return false;
805 }
806 if (offscreenCanvas->renderingContext()->isPlaceholder()) {
807 errorCode = ExceptionCode::InvalidStateError;
808 return false;
809 }
810 if (horizontalDimension > offscreenCanvas->width() || verticalDimension > offscreenCanvas->height()) {
811 errorCode = ExceptionCode::OperationError;
812 return false;
813 }
814 return true;
815 }
816#endif
817 );
818}
819
820// FIXME: https://bugs.webkit.org/show_bug.cgi?id=263692 - this code should be removed, it is to unblock
821// compiler <-> pipeline dependencies
822#if PLATFORM(COCOA)(defined 1 && 1)
823static uint32_t NODELETE[[clang::annotate_type("webkit.nodelete")]] convertRGBA8888ToRGB10A2(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
824{
825 uint32_t r0 = (static_cast<uint32_t>(r) << 2) | (static_cast<uint32_t>(r) >> 6);
826 uint32_t g0 = (static_cast<uint32_t>(g) << 2) | (static_cast<uint32_t>(g) >> 6);
827 uint32_t b0 = (static_cast<uint32_t>(b) << 2) | (static_cast<uint32_t>(b) >> 6);
828 uint32_t a0 = (static_cast<uint32_t>(a) >> 6);
829 return r0 | (g0 << 10) | (b0 << 20) | (a0 << 30);
830}
831#endif
832
833static void populdateXYFromOrigin(const GPUOrigin2D& origin2D, uint32_t& x, uint32_t& y)
834{
835 WTF::switchOn(origin2D, [&](const Vector<GPUIntegerCoordinate>& vector) {
836 x = vector.size() ? vector[0] : 0;
837 y = vector.size() > 1 ? vector[1] : 0;
838 }, [&](const GPUOrigin2DDict& origin2D) {
839 x = origin2D.x;
840 y = origin2D.y;
841 });
842}
843
844static MallocSpan<uint8_t> copyToDestinationFormat(std::span<const uint8_t> rgbaBytes, GPUTextureFormat format, bool& supportedFormat, size_t rows, bool flipY, bool premultiplyAlpha, const std::optional<GPUOrigin2D>& sourceOrigin)
845{
846 uint32_t sourceX = 0, sourceY = 0;
847 if (sourceOrigin)
848 populdateXYFromOrigin(*sourceOrigin, sourceX, sourceY);
849
850#if PLATFORM(COCOA)(defined 1 && 1)
851 auto sizeInBytes = rgbaBytes.size();
852 auto flipAndPremultiply = [&](auto& data, bool flipY, bool premultiplyAlpha, auto oneValue) {
853 if (!rows || (!flipY && !premultiplyAlpha))
854 return;
855
856 auto typedBytes = data.mutableSpan();
857 size_t widthInElements = typedBytes.size() / rows;
858 if (premultiplyAlpha) {
859 RELEASE_ASSERT(!(widthInElements % 4))do { if (__builtin_expect(!!(!(!(widthInElements % 4))), 0)) do
{ WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(859, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/Modules/WebGPU/GPUQueue.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
860 using T = decltype(oneValue);
861 float invOneValue = 1.f / oneValue;
862 for (size_t i = 0; i < sizeInBytes; i += 4) {
863 float alpha = typedBytes[i + 3];
864 typedBytes[i] = static_cast<T>(typedBytes[i] * alpha * invOneValue);
865 typedBytes[i + 1] = static_cast<T>(typedBytes[i + 1] * alpha * invOneValue);
866 typedBytes[i + 2] = static_cast<T>(typedBytes[i + 2] * alpha * invOneValue);
867 }
868 }
869
870 if (flipY && sourceY < rows && !sourceY && !sourceX) {
871 for (size_t y = 0, y0 = rows - 1 - sourceY; y < y0; ++y, --y0) {
872 for (size_t x = 0; x < widthInElements; ++x)
873 std::swap(typedBytes[y0 * widthInElements + x], typedBytes[y * widthInElements + x]);
874 }
875 }
876 };
877#endif
878
879 supportedFormat = true;
880#if PLATFORM(COCOA)(defined 1 && 1)
881 switch (format) {
882 case GPUTextureFormat::R8unorm: {
883 auto data = MallocSpan<uint8_t>::malloc(sizeInBytes / 4);
884 if (premultiplyAlpha) {
885 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
886 data[i0] = static_cast<uint8_t>((rgbaBytes[i] * static_cast<uint32_t>(rgbaBytes[i + 3])) / 255);
887 } else {
888 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
889 data[i0] = rgbaBytes[i];
890 }
891
892 flipAndPremultiply(data, flipY, false, 255);
893 return data;
894 }
895
896 // 16-bit formats
897 case GPUTextureFormat::R16float: {
898 auto data = MallocSpan<__fp16>::malloc(sizeInBytes / 2);
899 if (premultiplyAlpha) {
900 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
901 data[i0] = (rgbaBytes[i] / 255.f) * (rgbaBytes[i + 3] / 255.f);
902 } else {
903 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
904 data[i0] = rgbaBytes[i] / 255.f;
905 }
906
907 flipAndPremultiply(data, flipY, false, 1.f);
908 return data;
909 }
910
911 case GPUTextureFormat::Rg8unorm: {
912 auto data = MallocSpan<uint8_t>::malloc(sizeInBytes / 2);
913 if (premultiplyAlpha) {
914 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
915 data[i0] = static_cast<uint8_t>((rgbaBytes[i] * static_cast<uint32_t>(rgbaBytes[i + 3])) / 255);
916 data[i0 + 1] = static_cast<uint8_t>((rgbaBytes[i + 1] * static_cast<uint32_t>(rgbaBytes[i + 3])) / 255);
917 }
918 } else {
919 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
920 data[i0] = rgbaBytes[i];
921 data[i0 + 1] = rgbaBytes[i + 1];
922 }
923 }
924
925 flipAndPremultiply(data, flipY, false, 255);
926 return data;
927 }
928
929 // 32-bit formats
930 case GPUTextureFormat::R32float: {
931 auto data = MallocSpan<float>::malloc(sizeInBytes);
932 if (premultiplyAlpha) {
933 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
934 data[i0] = (rgbaBytes[i] / 255.f) * (rgbaBytes[i + 3] / 255.f);
935 } else {
936 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
937 data[i0] = rgbaBytes[i] / 255.f;
938 }
939
940 flipAndPremultiply(data, flipY, false, 1.f);
941 return data;
942 }
943
944 case GPUTextureFormat::Rg16float: {
945 auto data = MallocSpan<__fp16>::malloc(sizeInBytes);
946 if (premultiplyAlpha) {
947 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
948 data[i0] = (rgbaBytes[i] / 255.f) * (rgbaBytes[i + 3] / 255.f);
949 data[i0 + 1] = (rgbaBytes[i + 1] / 255.f) * (rgbaBytes[i + 3] / 255.f);
950 }
951 } else {
952 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
953 data[i0] = rgbaBytes[i] / 255.f;
954 data[i0 + 1] = rgbaBytes[i + 1] / 255.f;
955 }
956 }
957
958 flipAndPremultiply(data, flipY, false, 1.f);
959 return data;
960 }
961
962 case GPUTextureFormat::Rgba8unorm:
963 case GPUTextureFormat::Rgba8unormSRGB: {
964 if (flipY || premultiplyAlpha || sourceX || sourceY) {
965 auto data = MallocSpan<uint8_t>::malloc(sizeInBytes);
966 memcpySpan(data.mutableSpan(), rgbaBytes);
967 flipAndPremultiply(data, flipY, premultiplyAlpha, 255);
968 return data;
969 }
970 return { };
971 }
972 case GPUTextureFormat::Bgra8unorm:
973 case GPUTextureFormat::Bgra8unormSRGB: {
974 auto data = MallocSpan<uint8_t>::malloc(sizeInBytes);
975 for (size_t i = 0; i < sizeInBytes; i += 4) {
976 data[i] = rgbaBytes[i + 2];
977 data[i + 1] = rgbaBytes[i + 1];
978 data[i + 2] = rgbaBytes[i];
979 data[i + 3] = rgbaBytes[i + 3];
980 }
981 flipAndPremultiply(data, flipY, premultiplyAlpha, 255);
982 return data;
983 }
984 case GPUTextureFormat::Rgb10a2unorm: {
985 auto data = MallocSpan<uint32_t>::malloc(sizeInBytes);
986 if (flipY || premultiplyAlpha || sourceX || sourceY) {
987 auto copySpan = MallocSpan<uint8_t>::malloc(sizeInBytes);
988 memcpySpan(copySpan.mutableSpan(), rgbaBytes);
989 flipAndPremultiply(copySpan, flipY, premultiplyAlpha, 255);
990 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
991 data[i0] = convertRGBA8888ToRGB10A2(copySpan[i], copySpan[i + 1], copySpan[i + 2], copySpan[i + 3]);
992 } else {
993 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, ++i0)
994 data[i0] = convertRGBA8888ToRGB10A2(rgbaBytes[i], rgbaBytes[i + 1], rgbaBytes[i + 2], rgbaBytes[i + 3]);
995 }
996
997 return data;
998 }
999
1000 // 64-bit formats
1001 case GPUTextureFormat::Rg32float: {
1002 auto data = MallocSpan<float>::malloc((sizeInBytes / 2) * sizeof(float));
1003 if (premultiplyAlpha) {
1004 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
1005 data[i0] = (rgbaBytes[i] / 255.f) * (rgbaBytes[i + 3] / 255.f);
1006 data[i0 + 1] = (rgbaBytes[i + 1] / 255.f) * (rgbaBytes[i + 3] / 255.f);
1007 }
1008 } else {
1009 for (size_t i = 0, i0 = 0; i < sizeInBytes; i += 4, i0 += 2) {
1010 data[i0] = (rgbaBytes[i] / 255.f);
1011 data[i0 + 1] = (rgbaBytes[i + 1] / 255.f);
1012 }
1013 }
1014
1015 flipAndPremultiply(data, flipY, false, 1.f);
1016 return data;
1017 }
1018
1019 case GPUTextureFormat::Rgba16float: {
1020 auto data = MallocSpan<__fp16>::malloc(sizeInBytes * sizeof(__fp16));
1021 for (size_t i = 0; i < sizeInBytes; ++i)
1022 data[i] = rgbaBytes[i] / 255.f;
1023
1024 flipAndPremultiply(data, flipY, premultiplyAlpha, 1.f);
1025 return data;
1026 }
1027
1028 // 128-bit formats
1029 case GPUTextureFormat::Rgba32float: {
1030 auto data = MallocSpan<float>::malloc(sizeInBytes * sizeof(float));
1031 for (size_t i = 0; i < sizeInBytes; ++i)
1032 data[i] = rgbaBytes[i] / 255.f;
1033
1034 flipAndPremultiply(data, flipY, premultiplyAlpha, 1.f);
1035 return data;
1036 }
1037
1038 // Formats which are not allowed
1039 case GPUTextureFormat::R8snorm:
1040 case GPUTextureFormat::R8uint:
1041 case GPUTextureFormat::R8sint:
1042 case GPUTextureFormat::R16unorm:
1043 case GPUTextureFormat::R16snorm:
1044 case GPUTextureFormat::R16uint:
1045 case GPUTextureFormat::R16sint:
1046 case GPUTextureFormat::Rg8snorm:
1047 case GPUTextureFormat::Rg8uint:
1048 case GPUTextureFormat::Rg8sint:
1049 case GPUTextureFormat::R32uint:
1050 case GPUTextureFormat::R32sint:
1051 case GPUTextureFormat::Rg16unorm:
1052 case GPUTextureFormat::Rg16snorm:
1053 case GPUTextureFormat::Rg16uint:
1054 case GPUTextureFormat::Rg16sint:
1055 case GPUTextureFormat::Rgba32uint:
1056 case GPUTextureFormat::Rgba32sint:
1057 case GPUTextureFormat::Rgba8snorm:
1058 case GPUTextureFormat::Rgba8uint:
1059 case GPUTextureFormat::Rgba8sint:
1060 case GPUTextureFormat::Rgb9e5ufloat:
1061 case GPUTextureFormat::Rgb10a2uint:
1062 case GPUTextureFormat::Rg11b10ufloat:
1063 case GPUTextureFormat::Rg32uint:
1064 case GPUTextureFormat::Rg32sint:
1065 case GPUTextureFormat::Rgba16unorm:
1066 case GPUTextureFormat::Rgba16snorm:
1067 case GPUTextureFormat::Rgba16uint:
1068 case GPUTextureFormat::Rgba16sint:
1069 case GPUTextureFormat::Stencil8:
1070 case GPUTextureFormat::Depth16unorm:
1071 case GPUTextureFormat::Depth24plus:
1072 case GPUTextureFormat::Depth24plusStencil8:
1073 case GPUTextureFormat::Depth32float:
1074 case GPUTextureFormat::Depth32floatStencil8:
1075 case GPUTextureFormat::Bc1RgbaUnorm:
1076 case GPUTextureFormat::Bc1RgbaUnormSRGB:
1077 case GPUTextureFormat::Bc2RgbaUnorm:
1078 case GPUTextureFormat::Bc2RgbaUnormSRGB:
1079 case GPUTextureFormat::Bc3RgbaUnorm:
1080 case GPUTextureFormat::Bc3RgbaUnormSRGB:
1081 case GPUTextureFormat::Bc4RUnorm:
1082 case GPUTextureFormat::Bc4RSnorm:
1083 case GPUTextureFormat::Bc5RgUnorm:
1084 case GPUTextureFormat::Bc5RgSnorm:
1085 case GPUTextureFormat::Bc6hRgbUfloat:
1086 case GPUTextureFormat::Bc6hRgbFloat:
1087 case GPUTextureFormat::Bc7RgbaUnorm:
1088 case GPUTextureFormat::Bc7RgbaUnormSRGB:
1089 case GPUTextureFormat::Etc2Rgb8unorm:
1090 case GPUTextureFormat::Etc2Rgb8unormSRGB:
1091 case GPUTextureFormat::Etc2Rgb8a1unorm:
1092 case GPUTextureFormat::Etc2Rgb8a1unormSRGB:
1093 case GPUTextureFormat::Etc2Rgba8unorm:
1094 case GPUTextureFormat::Etc2Rgba8unormSRGB:
1095 case GPUTextureFormat::EacR11unorm:
1096 case GPUTextureFormat::EacR11snorm:
1097 case GPUTextureFormat::EacRg11unorm:
1098 case GPUTextureFormat::EacRg11snorm:
1099 case GPUTextureFormat::Astc4x4Unorm:
1100 case GPUTextureFormat::Astc4x4UnormSRGB:
1101 case GPUTextureFormat::Astc5x4Unorm:
1102 case GPUTextureFormat::Astc5x4UnormSRGB:
1103 case GPUTextureFormat::Astc5x5Unorm:
1104 case GPUTextureFormat::Astc5x5UnormSRGB:
1105 case GPUTextureFormat::Astc6x5Unorm:
1106 case GPUTextureFormat::Astc6x5UnormSRGB:
1107 case GPUTextureFormat::Astc6x6Unorm:
1108 case GPUTextureFormat::Astc6x6UnormSRGB:
1109 case GPUTextureFormat::Astc8x5Unorm:
1110 case GPUTextureFormat::Astc8x5UnormSRGB:
1111 case GPUTextureFormat::Astc8x6Unorm:
1112 case GPUTextureFormat::Astc8x6UnormSRGB:
1113 case GPUTextureFormat::Astc8x8Unorm:
1114 case GPUTextureFormat::Astc8x8UnormSRGB:
1115 case GPUTextureFormat::Astc10x5Unorm:
1116 case GPUTextureFormat::Astc10x5UnormSRGB:
1117 case GPUTextureFormat::Astc10x6Unorm:
1118 case GPUTextureFormat::Astc10x6UnormSRGB:
1119 case GPUTextureFormat::Astc10x8Unorm:
1120 case GPUTextureFormat::Astc10x8UnormSRGB:
1121 case GPUTextureFormat::Astc10x10Unorm:
1122 case GPUTextureFormat::Astc10x10UnormSRGB:
1123 case GPUTextureFormat::Astc12x10Unorm:
1124 case GPUTextureFormat::Astc12x10UnormSRGB:
1125 case GPUTextureFormat::Astc12x12Unorm:
1126 case GPUTextureFormat::Astc12x12UnormSRGB:
1127 supportedFormat = false;
1128 return { };
1129 }
1130
1131 return { };
1132#else
1133 UNUSED_PARAM(format)(void)format;
1134 UNUSED_PARAM(rgbaBytes)(void)rgbaBytes;
1135 UNUSED_PARAM(rows)(void)rows;
1136 UNUSED_PARAM(flipY)(void)flipY;
1137 UNUSED_PARAM(premultiplyAlpha)(void)premultiplyAlpha;
1138
1139 return { };
1140#endif
1141}
1142
1143ExceptionOr<void> GPUQueue::copyExternalImageToTexture(ScriptExecutionContext& context, const GPUImageCopyExternalImage& source, const GPUImageCopyTextureTagged& destination, const GPUExtent3D& copySize)
1144{
1145 ExceptionCode outErrorCode;
1146 if (!isStateValid(source.source, source.origin, copySize, outErrorCode))
1147 return Exception { outErrorCode, "GPUQueue.copyExternalImageToTexture: External image state is not valid"_s };
1148
1149 if (!isOriginClean(source.source, context))
1150 return Exception { ExceptionCode::SecurityError, "GPUQueue.copyExternalImageToTexture: Cross origin external images are not allowed in WebGPU"_s };
1151
1152 bool callbackScopeIsSafe { true };
1153 bool needsYFlip = source.flipY;
1154 bool needsPremultipliedAlpha = destination.premultipliedAlpha;
1155 auto backingCopySize = convertToBacking(copySize);
1156 imageBytesForSource(m_backing.get(), source, destination, needsYFlip, needsPremultipliedAlpha, backingCopySize, [&](std::span<const uint8_t> imageBytes, size_t columns, size_t rows) {
1157 RELEASE_ASSERT(callbackScopeIsSafe)do { if (__builtin_expect(!!(!(callbackScopeIsSafe)), 0)) do {
WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(1157, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/Modules/WebGPU/GPUQueue.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
1158 auto destinationTexture = destination.texture;
1159 auto sizeInBytes = imageBytes.size();
1160 if (!imageBytes.data() || !sizeInBytes || (imageBytes.size() % 4))
1161 return;
1162
1163 bool supportedFormat;
1164 auto newImageBytes = copyToDestinationFormat(imageBytes, destination.texture->format(), supportedFormat, rows, needsYFlip, needsPremultipliedAlpha, source.origin);
1165 uint32_t sourceX = 0, sourceY = 0;
1166 auto widthInBytes = (newImageBytes ? newImageBytes.sizeInBytes() : sizeInBytes) / rows;
1167 auto channels = widthInBytes / columns;
1168 GPUImageDataLayout dataLayout { 0, widthInBytes, rows };
1169
1170 if (source.origin && supportedFormat) {
1171 populdateXYFromOrigin(*source.origin, sourceX, sourceY);
1172
1173 if (sourceX || sourceY) {
1174 RELEASE_ASSERT(newImageBytes)do { if (__builtin_expect(!!(!(newImageBytes)), 0)) do { WTF::
isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(1174, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/Modules/WebGPU/GPUQueue.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
1175 auto copySizeWidth = dimension(copySize, 0);
1176 auto copySizeHeight = dimension(copySize, 1);
1177 for (size_t y = 0; y < copySizeHeight; ++y) {
1178 auto targetY = !needsYFlip ? (sourceY + y) : (sourceY + (copySizeHeight - 1 - y));
1179 for (size_t x = sourceX, x0 = 0; x0 < copySizeWidth; ++x, ++x0) {
1180 for (size_t c = 0; c < channels; ++c)
1181 newImageBytes[y * widthInBytes + x0 * channels + c] = newImageBytes[targetY * widthInBytes + x * channels + c];
1182 }
1183 }
1184 needsYFlip = false;
1185 }
1186 }
1187
1188 auto copyDestination = destination.convertToBacking();
1189
1190 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=263692 - this code should be removed once copyExternalImageToTexture
1191 // is implemented in the GPU process
1192 if (!supportedFormat || !(destinationTexture->usage() & GPUTextureUsage::RENDER_ATTACHMENT))
1193 copyDestination.mipLevel = INT_MAX2147483647;
1194
1195 m_backing->writeTexture(copyDestination, newImageBytes ? newImageBytes.span() : imageBytes, dataLayout.convertToBacking(), backingCopySize);
1196 });
1197 callbackScopeIsSafe = false;
1198
1199 return { };
1200}
1201
1202} // namespace WebCore