@@ -1401,6 +1401,8 @@ export const builtinNeedsDerivatives = (builtin: TextureBuiltin) =>
14011401 builtin === 'textureSample' ||
14021402 builtin === 'textureSampleBias' ||
14031403 builtin === 'textureSampleCompare' ;
1404+ // This returns true for `texture_depth_2d`, `texture_depth_cube` etc...
1405+ const isSingleChannelInput = ( textureType : string ) => textureType . startsWith ( 'texture_depth' ) ;
14041406
14051407const isCubeViewDimension = ( viewDescriptor ?: GPUTextureViewDescriptor ) =>
14061408 viewDescriptor ?. dimension === 'cube' || viewDescriptor ?. dimension === 'cube-array' ;
@@ -1550,6 +1552,39 @@ export function convertPerTexelComponentToResultFormat(
15501552 return out ;
15511553}
15521554
1555+ function swizzleComponentToTexelComponent (
1556+ src : PerTexelComponent < number > ,
1557+ component : GPUComponentSwizzle
1558+ ) : number {
1559+ switch ( component ) {
1560+ case '0' :
1561+ return 0 ;
1562+ case '1' :
1563+ return 1 ;
1564+ case 'r' :
1565+ return src . R ! ;
1566+ case 'g' :
1567+ return src . G ! ;
1568+ case 'b' :
1569+ return src . B ! ;
1570+ case 'a' :
1571+ return src . A ! ;
1572+ }
1573+ }
1574+
1575+ export function swizzleTexel (
1576+ src : PerTexelComponent < number > ,
1577+ swizzle : GPUTextureComponentSwizzle | undefined
1578+ ) : PerTexelComponent < number > {
1579+ swizzle = swizzle ?? 'rgba' ;
1580+ return {
1581+ R : swizzleComponentToTexelComponent ( src , swizzle [ 0 ] as GPUComponentSwizzle ) ,
1582+ G : swizzleComponentToTexelComponent ( src , swizzle [ 1 ] as GPUComponentSwizzle ) ,
1583+ B : swizzleComponentToTexelComponent ( src , swizzle [ 2 ] as GPUComponentSwizzle ) ,
1584+ A : swizzleComponentToTexelComponent ( src , swizzle [ 3 ] as GPUComponentSwizzle ) ,
1585+ } ;
1586+ }
1587+
15531588/**
15541589 * Convert RGBA result format to texel view format.
15551590 * Example, converts
@@ -1625,7 +1660,7 @@ const kDefaultValueForDepthTextureComponents: Record<TexelComponent, number> = {
16251660} as const ;
16261661
16271662/**
1628- * Applies a comparison function to each component of a texel.
1663+ * Applies a comparison function the R or Depth component of a texel.
16291664 */
16301665export function applyCompareToTexel (
16311666 components : TexelComponent [ ] ,
@@ -1686,6 +1721,7 @@ function getEffectiveLodClamp(
16861721 * mip level
16871722 */
16881723function softwareTextureReadMipLevel < T extends Dimensionality > (
1724+ t : GPUTest ,
16891725 call : TextureCall < T > ,
16901726 softwareTexture : SoftwareTexture ,
16911727 sampler : GPUSamplerDescriptor | undefined ,
@@ -1701,6 +1737,7 @@ function softwareTextureReadMipLevel<T extends Dimensionality>(
17011737 baseMipLevelSize ,
17021738 mipLevel
17031739 ) ;
1740+ const swizzle = softwareTexture . viewDescriptor . swizzle ;
17041741
17051742 const addressMode : GPUAddressMode [ ] =
17061743 call . builtin === 'textureSampleBaseClampToEdge'
@@ -1890,7 +1927,8 @@ function softwareTextureReadMipLevel<T extends Dimensionality>(
18901927 const v = load ( c ) ;
18911928 const postV = applyCompare ( call , sampler , rep . componentOrder , v ) ;
18921929 const rgba = convertPerTexelComponentToResultFormat ( postV , format ) ;
1893- out [ kRGBAComponents [ i ] ] = rgba [ component ] ;
1930+ const swizzled = swizzleTexel ( rgba , swizzle ) ;
1931+ out [ kRGBAComponents [ i ] ] = swizzled [ component ] ;
18941932 } ) ;
18951933 return out ;
18961934 }
@@ -1907,13 +1945,15 @@ function softwareTextureReadMipLevel<T extends Dimensionality>(
19071945 }
19081946 }
19091947
1910- return convertPerTexelComponentToResultFormat ( out , format ) ;
1948+ const rgba = convertPerTexelComponentToResultFormat ( out , format ) ;
1949+ return swizzleTexel ( rgba , swizzle ) ;
19111950 }
19121951 case 'textureLoad' : {
19131952 const out : PerTexelComponent < number > = isOutOfBoundsCall ( softwareTexture , call )
19141953 ? zeroValuePerTexelComponent ( rep . componentOrder )
19151954 : load ( call . coords ! ) ;
1916- return convertPerTexelComponentToResultFormat ( out , format ) ;
1955+ const rgba = convertPerTexelComponentToResultFormat ( out , format ) ;
1956+ return swizzleTexel ( rgba , swizzle ) ;
19171957 }
19181958 default :
19191959 unreachable ( ) ;
@@ -1932,7 +1972,7 @@ function softwareTextureReadLevel<T extends Dimensionality>(
19321972 mipLevel : number
19331973) : PerTexelComponent < number > {
19341974 if ( ! sampler ) {
1935- return softwareTextureReadMipLevel < T > ( call , softwareTexture , sampler , mipLevel ) ;
1975+ return softwareTextureReadMipLevel < T > ( t , call , softwareTexture , sampler , mipLevel ) ;
19361976 }
19371977
19381978 const { mipLevelCount } = getBaseMipLevelInfo ( softwareTexture ) ;
@@ -1943,8 +1983,8 @@ function softwareTextureReadLevel<T extends Dimensionality>(
19431983 const clampedMipLevel = clamp ( mipLevel , lodClampMinMax ) ;
19441984 const rootMipLevel = Math . floor ( clampedMipLevel ) ;
19451985 const nextMipLevel = Math . ceil ( clampedMipLevel ) ;
1946- const t0 = softwareTextureReadMipLevel < T > ( call , softwareTexture , sampler , rootMipLevel ) ;
1947- const t1 = softwareTextureReadMipLevel < T > ( call , softwareTexture , sampler , nextMipLevel ) ;
1986+ const t0 = softwareTextureReadMipLevel < T > ( t , call , softwareTexture , sampler , rootMipLevel ) ;
1987+ const t1 = softwareTextureReadMipLevel < T > ( t , call , softwareTexture , sampler , nextMipLevel ) ;
19481988 const weightType = call . builtin === 'textureSampleLevel' ? 'sampleLevelWeights' : 'identity' ;
19491989 const mix = getWeightForMipLevel ( t , stage , weightType , mipLevelCount , clampedMipLevel ) ;
19501990 assert ( mix >= 0 && mix <= 1 ) ;
@@ -1962,7 +2002,7 @@ function softwareTextureReadLevel<T extends Dimensionality>(
19622002 }
19632003 default : {
19642004 const baseMipLevel = Math . floor ( clamp ( mipLevel , lodClampMinMax ) + 0.5 ) ;
1965- return softwareTextureReadMipLevel < T > ( call , softwareTexture , sampler , baseMipLevel ) ;
2005+ return softwareTextureReadMipLevel < T > ( t , call , softwareTexture , sampler , baseMipLevel ) ;
19662006 }
19672007 }
19682008}
@@ -2178,6 +2218,8 @@ function isOutOfBoundsCall<T extends Dimensionality>(
21782218function isValidOutOfBoundsValue (
21792219 device : GPUDevice ,
21802220 softwareTexture : SoftwareTexture ,
2221+ builtin : TextureBuiltin ,
2222+ textureType : string ,
21812223 gotRGBA : PerTexelComponent < number > ,
21822224 maxFractionalDiff : number
21832225) {
@@ -2203,6 +2245,7 @@ function isValidOutOfBoundsValue(
22032245 }
22042246
22052247 // Can be any texel value
2248+ const swizzle = softwareTexture . viewDescriptor . swizzle ;
22062249 for ( let mipLevel = 0 ; mipLevel < softwareTexture . texels . length ; ++ mipLevel ) {
22072250 const mipTexels = softwareTexture . texels [ mipLevel ] ;
22082251 const size = virtualMipSize (
@@ -2216,10 +2259,15 @@ function isValidOutOfBoundsValue(
22162259 for ( let x = 0 ; x < size [ 0 ] ; ++ x ) {
22172260 for ( let sampleIndex = 0 ; sampleIndex < sampleCount ; ++ sampleIndex ) {
22182261 const texel = mipTexels . color ( { x, y, z, sampleIndex } ) ;
2219- const rgba = convertPerTexelComponentToResultFormat ( texel , mipTexels . format ) ;
2262+ const rgba = swizzleTexel (
2263+ convertPerTexelComponentToResultFormat ( texel , mipTexels . format ) ,
2264+ swizzle
2265+ ) ;
22202266 if (
22212267 texelsApproximatelyEqual (
22222268 device ,
2269+ builtin ,
2270+ textureType ,
22232271 gotRGBA ,
22242272 softwareTexture . descriptor . format ,
22252273 rgba ,
@@ -2250,14 +2298,22 @@ function okBecauseOutOfBounds<T extends Dimensionality>(
22502298 device : GPUDevice ,
22512299 softwareTexture : SoftwareTexture ,
22522300 call : TextureCall < T > ,
2301+ textureType : string ,
22532302 gotRGBA : PerTexelComponent < number > ,
22542303 maxFractionalDiff : number
22552304) {
22562305 if ( ! isOutOfBoundsCall ( softwareTexture , call ) ) {
22572306 return false ;
22582307 }
22592308
2260- return isValidOutOfBoundsValue ( device , softwareTexture , gotRGBA , maxFractionalDiff ) ;
2309+ return isValidOutOfBoundsValue (
2310+ device ,
2311+ softwareTexture ,
2312+ call . builtin ,
2313+ textureType ,
2314+ gotRGBA ,
2315+ maxFractionalDiff
2316+ ) ;
22612317}
22622318
22632319const kRGBAComponents = [
@@ -2274,6 +2330,8 @@ const kRComponent = [TexelComponent.R] as const;
22742330 */
22752331export function texelsApproximatelyEqual (
22762332 device : GPUDevice ,
2333+ builtin : TextureBuiltin ,
2334+ textureType : string ,
22772335 gotRGBA : PerTexelComponent < number > ,
22782336 gotFormat : GPUTextureFormat ,
22792337 expectRGBA : PerTexelComponent < number > ,
@@ -2292,11 +2350,7 @@ export function texelsApproximatelyEqual(
22922350 expectedFormat
22932351 ) ;
22942352
2295- const rgbaComponentsToCheck =
2296- isDepthOrStencilTextureFormat ( gotFormat ) && ! device . features . has ( 'texel-component-swizzle' )
2297- ? kRComponent
2298- : kRGBAComponents ;
2299-
2353+ const rgbaComponentsToCheck = getComponentsToCheck ( device , gotFormat , builtin , textureType ) ;
23002354 for ( const component of rgbaComponentsToCheck ) {
23012355 const g = gotRGBA [ component ] ! ;
23022356 const e = expectRGBA [ component ] ! ;
@@ -2371,6 +2425,27 @@ baseMipLevelSize: [${baseMipLevelSize.join(', ')}]
23712425physicalMipCount: ${ physicalMipLevelCount }
23722426 ` ;
23732427}
2428+
2429+ function getComponentsToCheck (
2430+ device : GPUDevice ,
2431+ format : GPUTextureFormat ,
2432+ builtin : TextureBuiltin ,
2433+ textureType : string
2434+ ) {
2435+ const returnsOneComponent = ! isBuiltinGather ( builtin ) && isSingleChannelInput ( textureType ) ;
2436+ if ( returnsOneComponent ) {
2437+ return kRComponent ;
2438+ }
2439+
2440+ const gbaUndefined =
2441+ isDepthOrStencilTextureFormat ( format ) && ! device . features . has ( 'texel-component-swizzle' ) ;
2442+ if ( gbaUndefined ) {
2443+ return kRComponent ;
2444+ }
2445+
2446+ return kRGBAComponents ;
2447+ }
2448+
23742449/**
23752450 * Checks the result of each call matches the expected result.
23762451 */
@@ -2518,6 +2593,8 @@ export async function checkCallResults<T extends Dimensionality>(
25182593 if (
25192594 texelsApproximatelyEqual (
25202595 t . device ,
2596+ call . builtin ,
2597+ textureType ,
25212598 gotRGBA ,
25222599 softwareTexture . descriptor . format ,
25232600 expectRGBA ,
@@ -2530,7 +2607,14 @@ export async function checkCallResults<T extends Dimensionality>(
25302607
25312608 if (
25322609 ! sampler &&
2533- okBecauseOutOfBounds ( t . device , softwareTexture , call , gotRGBA , callSpecificMaxFractionalDiff )
2610+ okBecauseOutOfBounds (
2611+ t . device ,
2612+ softwareTexture ,
2613+ call ,
2614+ textureType ,
2615+ gotRGBA ,
2616+ callSpecificMaxFractionalDiff
2617+ )
25342618 ) {
25352619 continue ;
25362620 }
@@ -2541,11 +2625,10 @@ export async function checkCallResults<T extends Dimensionality>(
25412625 // from the spec: https://gpuweb.github.io/gpuweb/#reading-depth-stencil
25422626 // depth and stencil values are D, ?, ?, ? unless texture-component-swizzle is enabled
25432627 // in which case it's D, 0, 0, 1
2544- const rgbaComponentsToCheck =
2545- ( isBuiltinGather ( call . builtin ) || ! isDepthOrStencilTextureFormat ( format ) ) &&
2546- t . device . features . has ( 'texture-component-swizzle' )
2547- ? kRGBAComponents
2548- : kRComponent ;
2628+ //
2629+ // That said, functions that take `texture_depth_??`, except textureGatherCompare, return f32, not vec4f.
2630+ // Our tests convert them to vec4f for reasons but we only care about the first channel.
2631+ const rgbaComponentsToCheck = getComponentsToCheck ( t . device , format , call . builtin , textureType ) ;
25492632
25502633 let bad = false ;
25512634 const diffs = rgbaComponentsToCheck . map ( component => {
@@ -5228,7 +5311,7 @@ ${stageWGSL}
52285311 ( sampler . minFilter === 'linear' ||
52295312 sampler . magFilter === 'linear' ||
52305313 sampler . mipmapFilter === 'linear' ) ;
5231- let sampleType : GPUTextureSampleType = textureType . startsWith ( 'texture_depth' )
5314+ let sampleType : GPUTextureSampleType = isSingleChannelInput ( textureType )
52325315 ? 'depth'
52335316 : isDepthTextureFormat ( format )
52345317 ? 'unfilterable-float'
0 commit comments