WebKit Bugzilla
Attachment 348433 Details for
Bug 188940
: [WHLSL] Implement texture types
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
bug-188940-20180829141930.patch (text/plain), 54.24 KB, created by
Myles C. Maxfield
on 2018-08-29 14:19:32 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2018-08-29 14:19:32 PDT
Size:
54.24 KB
patch
obsolete
>Subversion Revision: 235475 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 472bc3e9d6d4f8c0c0b2092c427c7931e85a3088..adcbc632872306cfd6390244ba008968b1b7cf49 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,29 @@ >+2018-08-29 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Implement texture types >+ https://bugs.webkit.org/show_bug.cgi?id=188940 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * WebGPUShadingLanguageRI/All.js: >+ * WebGPUShadingLanguageRI/Intrinsics.js: >+ (Intrinsics.): >+ (Intrinsics): >+ (Intrinsics.prototype.add): Deleted. >+ * WebGPUShadingLanguageRI/SPIRV.html: >+ * WebGPUShadingLanguageRI/StandardLibrary.js: >+ (let.standardLibrary): >+ * WebGPUShadingLanguageRI/Test.html: >+ * WebGPUShadingLanguageRI/Test.js: >+ (makeSampler): >+ (isPowerOf2): >+ (elementVectorSize): >+ (make1DTexture): >+ * WebGPUShadingLanguageRI/TextureOperations.js: Added. >+ (textureLoad): >+ (textureStore): >+ * WebGPUShadingLanguageRI/index.html: >+ > 2018-08-29 Jer Noble <jer.noble@apple.com> > > Muted elements do not have their Now Playing status updated when unmuted. >diff --git a/Tools/WebGPUShadingLanguageRI/All.js b/Tools/WebGPUShadingLanguageRI/All.js >index 9c2a37150c1e976b926cfbee23437520a8de4a47..cc07fdb516616d328f38445e95a8205392e5da5a 100644 >--- a/Tools/WebGPUShadingLanguageRI/All.js >+++ b/Tools/WebGPUShadingLanguageRI/All.js >@@ -150,6 +150,7 @@ load("SynthesizeStructAccessors.js"); > load("SynthesizeCopyConstructorOperator.js"); > load("SynthesizeDefaultConstructorOperator.js"); > load("TernaryExpression.js"); >+load("TextureOperations.js"); > load("TrapStatement.js"); > load("TypeDef.js"); > load("TypeDefResolver.js"); >diff --git a/Tools/WebGPUShadingLanguageRI/Intrinsics.js b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >index 79f59070daffb55a3f3a70a3b1badb4ce68cd4ef..8226ab5f98ed4b42ad6840d9d0ce501c869f4e57 100644 >--- a/Tools/WebGPUShadingLanguageRI/Intrinsics.js >+++ b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >@@ -330,7 +330,8 @@ class Intrinsics { > "native typedef sampler", > type => { > this.sampler = type; >- // FIXME: Figure out what to put here. >+ type.size = 1; >+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, {}); > }); > > for (let textureType of ["Texture1D", "RWTexture1D", "Texture1DArray", "RWTexture1DArray", "Texture2D", "RWTexture2D", "Texture2DArray", "RWTexture2DArray", "Texture3D", "RWTexture3D", "TextureCube"]) { >@@ -339,12 +340,16 @@ class Intrinsics { > `native typedef ${textureType}<${typeArgument}>`, > type => { > this[`${textureType}<${typeArgument}>`] = type; >+ type.size = 1; >+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, {}); > }); > for (let i = 2; i <= 4; ++i) { > this._map.set( > `native typedef ${textureType}<${typeArgument}${i}>`, > type => { > this[`${textureType}<${typeArgument}${i}>`] = type; >+ type.size = 1; >+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, {}); > }); > } > } >@@ -356,6 +361,8 @@ class Intrinsics { > `native typedef ${textureType}<${typeArgument}>`, > type => { > this[`${textureType}<${typeArgument}>`] = type; >+ type.size = 1; >+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, {}); > }); > } > } >@@ -914,6 +921,744 @@ class Intrinsics { > > for (let setter of BuiltinMatrixSetter.functions()) > this._map.set(setter.toString(), func => setter.instantiateImplementation(func)); >+ >+ for (let type of ["bool", "uchar", "ushort", "uint", "char", "short", "int", "half", "float"]) { >+ this._map.set( >+ `native ${type} Sample(Texture1D<${type}>,sampler,float location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Sample(Texture1D<${type}>,sampler,float location,int offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture1D<${type}>,int2 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1)])); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture1D<${type}>,int2 location,int offset)`, >+ func => { >+ func.implementation = function ([texture, location, offset]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1) + offset.loadValue()])); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(Texture1D<${type}>,uint MipLevel,uint* thread Width,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (mipID >= tex.length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ width.loadValue().copyFrom(EPtr.box(tex[mipID].length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native ${type} Sample(Texture1DArray<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Sample(Texture1DArray<${type}>,sampler,float2 location,int offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture1DArray<${type}>,int3 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2)])); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture1DArray<${type}>,int3 location,int offset)`, >+ func => { >+ func.implementation = function ([texture, location, offset]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2) + offset.loadValue()])); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(Texture1DArray<${type}>,uint MipLevel,uint* thread Width,uint* thread Elements,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, elements, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "No elements in the texture array"); >+ if (mipID >= tex[0].length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ width.loadValue().copyFrom(EPtr.box(tex[0][mipID].length), 1); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native ${type} Sample(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Sample(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleBias(Texture2D<${type}>,sampler,float2 location,float Bias)`, >+ func => { >+ func.implementation = function([texture, sampler, location, bias]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleBias(Texture2D<${type}>,sampler,float2 location,float Bias,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, bias, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleGrad(Texture2D<${type}>,sampler,float2 location,float2 DDX,float2 DDY)`, >+ func => { >+ func.implementation = function([texture, sampler, location, ddx, ddy]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleGrad(Texture2D<${type}>,sampler,float2 location,float2 DDX,float2 DDY,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, ddx, ddy, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleLevel(Texture2D<${type}>,sampler,float2 location,float LOD)`, >+ func => { >+ func.implementation = function([texture, sampler, location, lod]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleLevel(Texture2D<${type}>,sampler,float2 location,float LOD,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, lod, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function(([texture, sampler, location])) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture2D<${type}>,sampler,float2 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture2D<${type}>,sampler,float2 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture2D<${type}>,int3 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2)])); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture2D<${type}>,int3 location,int2 offset)`, >+ func => { >+ func.implementation = function ([texture, location, offset]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1) + offset.get(0), location.get(2) + offset.get(1)])); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(Texture2D<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, height, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (mipID >= tex.length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ if (tex[mipID].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ height.loadValue().copyFrom(EPtr.box(tex[mipID].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[mipID][0].length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native ${type} Sample(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Sample(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleBias(Texture2DArray<${type}>,sampler,float3 location,float Bias)`, >+ func => { >+ func.implementation = function([texture, sampler, location, bias]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleBias(Texture2DArray<${type}>,sampler,float3 location,float Bias,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, bias, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleGrad(Texture2DArray<${type}>,sampler,float3 location,float2 DDX,float2 DDY)`, >+ func => { >+ func.implementation = function([texture, sampler, location, ddx, ddy]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleGrad(Texture2DArray<${type}>,sampler,float3 location,float2 DDX,float2 DDY,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, ddx, ddy, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleLevel(Texture2DArray<${type}>,sampler,float3 location,float LOD)`, >+ func => { >+ func.implementation = function([texture, sampler, location, lod]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleLevel(Texture2DArray<${type}>,sampler,float3 location,float LOD,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, lod, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture2DArray<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture2DArray<${type}>,sampler,float3 location,int2 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture2DArray<${type}>,int4 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2), location.get(3)])); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture2DArray<${type}>,int4 location,int2 offset)`, >+ func => { >+ func.implementation = function ([texture, location, offset]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2) + offset.get(0), location.get(3) + offset.get(1)])); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(Texture2DArray<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread Elements,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, height, elements, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "No elements in the texture array"); >+ if (mipID >= tex[0].length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ if (tex[0][mipID].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ height.loadValue().copyFrom(EPtr.box(tex[0][mipID].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][mipID][0].length), 1); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native ${type} Sample(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Sample(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture3D<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(Texture3D<${type}>,sampler,float3 location,int3 offset)`, >+ func => { >+ func.implementation = function([texture, sampler, location, offset]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture3D<${type}>,int4 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2), location.get(3)])); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(Texture3D<${type}>,int4 location,int3 offset)`, >+ func => { >+ func.implementation = function ([texture, location, offset]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1) + offset.get(0), location.get(2) + offset.get(1), location.get(3) + offset.get(2)])); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(Texture3D<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread Depth,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, height, depth, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (mipID >= tex.length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ if (tex[mipID].length == 0) >+ throw new WTrapError("[load]", "Texture has zero depth"); >+ if (tex[mipID][0].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ depth.loadValue().copyFrom(EPtr.box(tex[mipID].length), 1); >+ height.loadValue().copyFrom(EPtr.box(tex[mipID][0].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[mipID][0][0].length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native ${type} Sample(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleBias(TextureCube<${type}>,sampler,float3 location,float Bias)`, >+ func => { >+ func.implementation = function([texture, sampler, location, bias]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleGrad(TextureCube<${type}>,sampler,float3 location,float3 DDX,float3 DDY)`, >+ func => { >+ func.implementation = function([texture, sampler, location, ddx, ddy]) { >+ } >+ }); >+ this._map.set( >+ `native ${type} SampleLevel(TextureCube<${type}>,sampler,float3 location,float LOD)`, >+ func => { >+ func.implementation = function([texture, sampler, location, lod]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 Gather(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherRed(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherGreen(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherBlue(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native ${type}4 GatherAlpha(TextureCube<${type}>,sampler,float3 location)`, >+ func => { >+ func.implementation = function([texture, sampler, location]) { >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(TextureCube<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`, >+ func => { >+ func.implementation = function([texture, miplevel, width, height, numberOfLevels]) { >+ let tex = texture.loadValue(); >+ let mipID = miplevel.loadValue(); >+ if (tex.length != 6) >+ throw new WTrapError("[load]", "Cube texture doesn't have 6 faces"); >+ if (mipID >= tex[0].length) >+ throw new WTrapError("[load]", "Reading from nonexistant mip level of texture"); >+ if (tex[0][mipID].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ height.loadValue().copyFrom(EPtr.box(tex[0][mipID].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][mipID][0].length), 1); >+ numberOfLevels.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ >+ this._map.set( >+ `native void GetDimensions(RWTexture1D<${type}>,uint* thread Width)`, >+ func => { >+ func.implementation = function([texture, width]) { >+ width.loadValue().copyFrom(EPtr.box(texture.loadValue().length), 1); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(RWTexture1D<${type}>,float* thread Width)`, >+ func => { >+ func.implementation = function([texture, width]) { >+ width.loadValue().copyFrom(EPtr.box(texture.loadValue().length), 1); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(RWTexture1D<${type}>,int location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.loadValue()])); >+ } >+ }); >+ this._map.set( >+ `native void Store(RWTexture1D<${type}>,${type},uint)`, >+ func => { >+ func.implementation = function ([texture, value, location]) { >+ textureStore(texture.loadValue(), value.loadValue(), [location.loadValue()]); >+ } >+ }); >+ >+ this._map.set( >+ `native void GetDimensions(RWTexture1DArray<${type}>,uint* thread Width,uint* thread Elements)`, >+ func => { >+ func.implementation = function([texture, width, elements]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no elements"); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(RWTexture1DArray<${type}>,float* thread Width,uint* thread Elements)`, >+ func => { >+ func.implementation = function([texture, width, elements]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no elements"); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(RWTexture1DArray<${type}>,int2 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1)])); >+ } >+ }); >+ this._map.set( >+ `native void Store(RWTexture1DArray<${type}>,${type},uint2)`, >+ func => { >+ func.implementation = function ([texture, value, location]) { >+ textureStore(texture.loadValue(), value.loadValue(), [location.get(0), location.get(1)]); >+ } >+ }); >+ >+ this._map.set( >+ `native void GetDimensions(RWTexture2D<${type}>,uint* thread Width,uint* thread Height)`, >+ func => { >+ func.implementation = function([texture, width, height]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ height.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(RWTexture2D<${type}>,float* thread Width,float* thread Height)`, >+ func => { >+ func.implementation = function([texture, width, height]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ height.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(RWTexture2D<${type}>,int2 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1)])); >+ } >+ }); >+ this._map.set( >+ `native void Store(RWTexture2D<${type}>,${type},uint2)`, >+ func => { >+ func.implementation = function ([texture, value, location]) { >+ textureStore(texture.loadValue(), value.loadValue(), [location.get(0), location.get(1)]); >+ } >+ }); >+ >+ this._map.set( >+ `native void GetDimensions(RWTexture2DArray<${type}>,uint* thread Width,uint* thread Height,uint* thread Elements)`, >+ func => { >+ func.implementation = function([texture, width, height, elements]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no elements"); >+ if (tex[0].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ height.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(RWTexture2DArray<${type}>,float* thread Width,float* thread Height,float* thread Elements)`, >+ func => { >+ func.implementation = function([texture, width, height, elements]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no elements"); >+ if (tex[0].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ elements.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ height.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(RWTexture2DArray<${type}>,int3 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2)])); >+ } >+ }); >+ this._map.set( >+ `native void Store(RWTexture2DArray<${type}>,${type},uint3)`, >+ func => { >+ func.implementation = function ([texture, value, location]) { >+ textureStore(texture.loadValue(), value.loadValue(), [location.get(0), location.get(1), location.get(2)]); >+ } >+ }); >+ >+ this._map.set( >+ `native void GetDimensions(RWTexture3D<${type}>,uint* thread Width,uint* thread Height,uint* thread Depth)`, >+ func => { >+ func.implementation = function([texture, width, height, depth]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no depth"); >+ if (tex[0].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ depth.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ height.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native void GetDimensions(RWTexture3D<${type}>,float* thread Width,float* thread Height,float* thread Depth)`, >+ func => { >+ func.implementation = function([texture, width, height, depth]) { >+ let tex = texture.loadValue(); >+ if (tex.length == 0) >+ throw new WTrapError("[load]", "Texture has no depth"); >+ if (tex[0].length == 0) >+ throw new WTrapError("[load]", "Texture has no rows"); >+ depth.loadValue().copyFrom(EPtr.box(tex.length), 1); >+ height.loadValue().copyFrom(EPtr.box(tex[0].length), 1); >+ width.loadValue().copyFrom(EPtr.box(tex[0][0].length), 1); >+ } >+ }); >+ this._map.set( >+ `native ${type} Load(RWTexture3D<${type}>,int3 location)`, >+ func => { >+ func.implementation = function ([texture, location]) { >+ return EPtr.box(textureLoad(texture.loadValue(), [location.get(0), location.get(1), location.get(2)])); >+ } >+ }); >+ this._map.set( >+ `native void Store(RWTexture3D<${type}>,${type},uint3)`, >+ func => { >+ func.implementation = function ([texture, value, location]) { >+ textureStore(texture.loadValue(), value.loadValue(), [location.get(0), location.get(1), location.get(2)]); >+ } >+ }); >+ >+ function boxVector(a) >+ { >+ let result = new EPtr(new EBuffer(a.length), 0); >+ for (let i = 0; i < a.length; ++i) >+ result.set(i, a[i]); >+ return result; >+ } >+ >+ for (let length of [2, 3, 4]) { >+ } > } > > add(thing) >diff --git a/Tools/WebGPUShadingLanguageRI/SPIRV.html b/Tools/WebGPUShadingLanguageRI/SPIRV.html >index 78d008f835f9e9c234ef2df6d6deea3f7426ce65..ddc65e367dd999ddb17d29cf6c5c6e62541d2a71 100644 >--- a/Tools/WebGPUShadingLanguageRI/SPIRV.html >+++ b/Tools/WebGPUShadingLanguageRI/SPIRV.html >@@ -133,6 +133,7 @@ td { > <script src="SynthesizeCopyConstructorOperator.js"></script> > <script src="SynthesizeDefaultConstructorOperator.js"></script> > <script src="TernaryExpression.js"></script> >+ <script src="TextureOperations.js"></script> > <script src="TrapStatement.js"></script> > <script src="TypeDef.js"></script> > <script src="TypeDefResolver.js"></script> >diff --git a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >index 6a33236617a431bd8239baa469d3ed80c1a9a02f..8576770e65dd776b81f0b89331b5798abca880a4 100644 >--- a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >+++ b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >@@ -1897,9 +1897,9 @@ let standardLibrary = (function() { > print(`native void InterlockedCompareExchange(thread atomic_${type}*, ${type}, ${type}, thread ${type}*);`); > } > print(); >- >+ */ > for (var type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) { >- for (var length of [``, `2`, `3`, `4`]) { >+ for (var length of [``/*, `2`, `3`, `4`*/]) { > print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location);`); > print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location, int offset);`); > print(`native ${type}${length} Load(Texture1D<${type}${length}>, int2 location);`); >@@ -2010,7 +2010,7 @@ let standardLibrary = (function() { > print(); > } > } >- >+ /* > for (var type of [`half`, `float`]) { > print(`native ${type} Sample(TextureDepth2D<${type}>, sampler, float2 location);`); > print(`native ${type} Sample(TextureDepth2D<${type}>, sampler, float2 location, int2 offset);`); >diff --git a/Tools/WebGPUShadingLanguageRI/Test.html b/Tools/WebGPUShadingLanguageRI/Test.html >index 607a6953253da727b1de37678ec388b4fa240405..0de791cbd369d407fcf269d0f0d3096c5a7689e6 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.html >+++ b/Tools/WebGPUShadingLanguageRI/Test.html >@@ -127,6 +127,7 @@ > <script src="SynthesizeCopyConstructorOperator.js"></script> > <script src="SynthesizeDefaultConstructorOperator.js"></script> > <script src="TernaryExpression.js"></script> >+<script src="TextureOperations.js"></script> > <script src="TrapStatement.js"></script> > <script src="TypeDef.js"></script> > <script src="TypeDefResolver.js"></script> >diff --git a/Tools/WebGPUShadingLanguageRI/Test.js b/Tools/WebGPUShadingLanguageRI/Test.js >index ab96bc477f7f1e29dbdf62f5260ce49e5e7100d8..37da4610ce4e0ef26d2067ff5b1e12a198342604 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.js >+++ b/Tools/WebGPUShadingLanguageRI/Test.js >@@ -94,6 +94,148 @@ function makeEnum(program, enumName, value) > return TypedValue.box(enumType, enumMember.value.unifyNode.valueForSelectedType); > } > >+function makeSampler(program, samplerData) >+{ >+ // enum AddressMode { >+ // "clampToEdge", >+ // "repeat", >+ // "mirrorRepeat", >+ // "clampToBorderColor" >+ // } >+ // >+ // enum Filter { >+ // "nearest", >+ // "linear" >+ // } >+ // >+ // enum CompareFunction { >+ // "never", >+ // "less", >+ // "equal", >+ // "lessEqual", >+ // "greater", >+ // "notEqual", >+ // "greaterEqual", >+ // "always" >+ // } >+ // >+ // enum BorderColor { >+ // "transparentBlack", >+ // "opaqueBlack", >+ // "opaqueWhite" >+ // } >+ // >+ // dictionary SamplerData { >+ // AddressMode rAddressMode = "clampToEdge", >+ // AddressMode sAddressMode = "clampToEdge", >+ // AddressMode tAddressMode = "clampToEdge", >+ // Filter minFilter = "nearest", >+ // Filter magFilter = "nearest", >+ // Filter mipFilter = "nearest", >+ // float lodMinClamp = 0, >+ // float lodMaxClamp = FLT_MAX, >+ // unsigned long maxAnisotropy = 1, >+ // boolean normalizedCoordinates = true, >+ // CompareFunction compareFunction = "never", >+ // BorderColor borderColor = "transparentBlack" >+ // } >+ // >+ return TypedValue.box(program.intrinsics.sampler, samplerData); >+} >+ >+function isPowerOf2(x) >+{ >+ return x && (x & (x - 1)) === 0; >+} >+ >+function elementVectorSize(elementType) >+{ >+ switch (elementType) { >+ case "bool": >+ case "uchar": >+ case "ushort": >+ case "uint": >+ case "char": >+ case "short": >+ case "int": >+ case "half": >+ case "float": >+ return null; >+ case "bool2": >+ case "uchar2": >+ case "ushort2": >+ case "uint2": >+ case "char2": >+ case "short2": >+ case "int2": >+ case "half2": >+ case "float2": >+ return 2; >+ case "bool3": >+ case "uchar3": >+ case "ushort3": >+ case "uint3": >+ case "char3": >+ case "short3": >+ case "int3": >+ case "half3": >+ case "float3": >+ return 3; >+ case "bool4": >+ case "uchar4": >+ case "ushort4": >+ case "uint4": >+ case "char4": >+ case "short4": >+ case "int4": >+ case "half4": >+ case "float4": >+ return 4; >+ default: >+ throw new Error("Unknown vector element type"); >+ } >+} >+ >+function make1DTexture(program, mipmaps, elementType) >+{ >+ var vectorSize = elementVectorSize(elementType); >+ >+ if (!(mipmaps instanceof Array)) >+ throw new Error("Texture needs to be an array of mipmaps"); >+ if (mipmaps.length == 0) >+ throw new Error("Need to have at least 1 mipmap"); >+ var size = mipmaps[0].length; >+ if (!isPowerOf2(size)) >+ throw new Error("Textures must be power-of-two sized"); >+ for (var mipmap of mipmaps) { >+ if (size == 0) >+ throw new Error("Cannot have zero-sized mipmap"); >+ if (!(mipmap instanceof Array)) >+ throw new Error("Each mipmap of a texture needs to be an array of values"); >+ if (mipmap.length != size) >+ throw new Error("Each mipmap of a texture must be half as big as the previous one"); >+ for (var element of mipmap) { >+ if (vectorSize == null && (typeof element) != "number") { >+ throw new Error(`${elementType} texture element must be a number`); >+ } else if (vectorSize != null) { >+ if (!(element instanceof Array)) >+ throw new Error(`${elementType} texture element must be an array`); >+ if (element.size != vectorSize) >+ throw new Error("Wrong number of components in texture element"); >+ for (var component of element) { >+ if ((typeof component) != "number") >+ throw new Error("Component needs to be a number"); >+ } >+ } >+ } >+ if (size == 1) >+ size = 0; >+ else >+ size /= 2; >+ } >+ return TypedValue.box(program.intrinsics[`Texture1D<${elementType}>`], mipmaps); >+} >+ > function checkNumber(program, result, expected) > { > if (!result.type.unifyNode.isNumber) >@@ -5451,6 +5593,35 @@ tests.halfSimpleMath = function() { > checkHalf(program, callFunction(program, "foo", [makeHalf(program, 7), makeHalf(program, -2)]), -3.5); > } > >+tests.textureDimensions = function() { >+ let program = doPrep(` >+ uint foo(Texture1D<float> texture) { >+ uint width; >+ uint numberOfLevels; >+ GetDimensions(texture, 0, &width, &numberOfLevels); >+ return width; >+ } >+ uint bar(Texture1D<float> texture) { >+ uint width; >+ uint numberOfLevels; >+ GetDimensions(texture, 0, &width, &numberOfLevels); >+ return numberOfLevels; >+ } >+ `); >+ checkUint(program, callFunction(program, "foo", [make1DTexture(program, [[1, 7, 14, 79], [13, 16], [15]], "float")]), 4); >+ checkUint(program, callFunction(program, "bar", [make1DTexture(program, [[1, 7, 14, 79], [13, 16], [15]], "float")]), 3); >+} >+ >+tests.textureLoad = function() { >+ let program = doPrep(` >+ float foo(Texture1D<float> texture, int mipmap, int location) { >+ return Load(texture, int2(mipmap, location)); >+ } >+ `); >+ checkFloat(program, callFunction(program, "foo", [make1DTexture(program, [[1, 7, 14, 79], [13, 16], [15]], "float"), makeInt(program, 0), makeInt(program, 1)]), 7); >+ checkFloat(program, callFunction(program, "foo", [make1DTexture(program, [[1, 7, 14, 79], [13, 16], [15]], "float"), makeInt(program, 1), makeInt(program, 1)]), 16); >+} >+ > okToTest = true; > > let testFilter = /.*/; // run everything by default >diff --git a/Tools/WebGPUShadingLanguageRI/TextureOperations.js b/Tools/WebGPUShadingLanguageRI/TextureOperations.js >new file mode 100644 >index 0000000000000000000000000000000000000000..babac4b6db690a66fe9974e88ed989534a9201b9 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/TextureOperations.js >@@ -0,0 +1,50 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+"use strict"; >+ >+function textureLoad(texture, path) >+{ >+ for (var index of path) { >+ if (index < 0 || index >= texture.length) >+ throw new WTrapError("[Load]", "Texture read out of bounds"); >+ texture = texture[index]; >+ } >+ return texture; >+} >+ >+function textureStore(texture, value, path) >+{ >+ do { >+ if (path.length == 0) >+ throw new Error("Zero-length store path"); >+ if (path.length == 1) { >+ texture[path[0]] = value; >+ return; >+ } else { >+ texture = texture[path[0]]; >+ path.shift(); >+ } >+ } while (true); >+} >diff --git a/Tools/WebGPUShadingLanguageRI/index.html b/Tools/WebGPUShadingLanguageRI/index.html >index 65a86411b3e770b557b41acc7e414def42403013..8366bb18d170e93f800df5822fa5eafeb43bed83 100644 >--- a/Tools/WebGPUShadingLanguageRI/index.html >+++ b/Tools/WebGPUShadingLanguageRI/index.html >@@ -127,6 +127,7 @@ > <script src="SynthesizeCopyConstructorOperator.js"></script> > <script src="SynthesizeDefaultConstructorOperator.js"></script> > <script src="TernaryExpression.js"></script> >+<script src="TextureOperations.js"></script> > <script src="TrapStatement.js"></script> > <script src="TypeDef.js"></script> > <script src="TypeDefResolver.js"></script>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188940
:
348066
|
348347
|
348365
|
348376
|
348433
|
348459
|
348464
|
348467
|
348521
|
348581
|
348582
|
348607
|
348661
|
348687
|
348695
|
348698
|
348705
|
348717
|
348718
|
348723
|
348724
|
348726
|
348727
|
348752
|
348758
|
348775
|
348791
|
348797
|
348798
|
348800
|
348801
|
348804