@@ -14,6 +14,7 @@ import { UniqueFeaturesOrLimitsGPUTest } from '../../../../gpu_test.js';
14
14
import {
15
15
isIdentitySwizzle ,
16
16
kSwizzleTests ,
17
+ swizzlesAreTheSame ,
17
18
swizzleSpecToGPUTextureComponentSwizzle ,
18
19
} from './texture_component_swizzle_utils.js' ;
19
20
@@ -80,3 +81,120 @@ g.test('no_render_nor_storage')
80
81
texture . createView ( { swizzle } ) ;
81
82
} , shouldError ) ;
82
83
} ) ;
84
+
85
+ g . test ( 'compatibility_mode' )
86
+ . desc (
87
+ `
88
+ Test that in compatibility mode, swizzles must be equivalent.
89
+ `
90
+ )
91
+ . beforeAllSubcases ( t => {
92
+ // MAINTENANCE_TODO: Remove this cast once texture-component-swizzle is added to @webgpu/types
93
+ t . selectDeviceOrSkipTestCase ( 'texture-component-swizzle' as GPUFeatureName ) ;
94
+ } )
95
+ . params ( u =>
96
+ u
97
+ . beginSubcases ( )
98
+ . combine ( 'swizzleSpec' , kSwizzleTests )
99
+ . combine ( 'otherSwizzleSpec' , kSwizzleTests )
100
+ . combine ( 'pipelineType' , [ 'render' , 'compute' ] as const )
101
+ )
102
+ . fn ( t => {
103
+ const { swizzleSpec, otherSwizzleSpec, pipelineType } = t . params ;
104
+ const swizzle = swizzleSpecToGPUTextureComponentSwizzle ( swizzleSpec ) ;
105
+ const otherSwizzle = swizzleSpecToGPUTextureComponentSwizzle ( otherSwizzleSpec ) ;
106
+
107
+ const module = t . device . createShaderModule ( {
108
+ code : `
109
+ @group(0) @binding(0) var tex0: texture_2d<f32>;
110
+ @group(1) @binding(0) var tex1: texture_2d<f32>;
111
+
112
+ @compute @workgroup_size(1) fn cs() {
113
+ _ = tex0;
114
+ _ = tex1;
115
+ }
116
+
117
+ @vertex fn vs() -> @builtin(position) vec4f {
118
+ return vec4f(0);
119
+ }
120
+
121
+ @fragment fn fs() -> @location(0) vec4f {
122
+ _ = tex0;
123
+ _ = tex1;
124
+ return vec4f(0);
125
+ }
126
+ ` ,
127
+ } ) ;
128
+
129
+ const pipeline =
130
+ pipelineType === 'compute'
131
+ ? t . device . createComputePipeline ( {
132
+ layout : 'auto' ,
133
+ compute : { module } ,
134
+ } )
135
+ : t . device . createRenderPipeline ( {
136
+ layout : 'auto' ,
137
+ vertex : { module } ,
138
+ fragment : { module, targets : [ { format : 'rgba8unorm' } ] } ,
139
+ } ) ;
140
+
141
+ const texture = t . createTextureTracked ( {
142
+ size : [ 1 ] ,
143
+ format : 'rgba8unorm' ,
144
+ usage : GPUTextureUsage . TEXTURE_BINDING ,
145
+ } ) ;
146
+
147
+ const bindGroup0 = t . device . createBindGroup ( {
148
+ layout : pipeline . getBindGroupLayout ( 0 ) ,
149
+ entries : [
150
+ {
151
+ binding : 0 ,
152
+ resource : texture . createView ( { swizzle } ) ,
153
+ } ,
154
+ ] ,
155
+ } ) ;
156
+
157
+ const bindGroup1 = t . device . createBindGroup ( {
158
+ layout : pipeline . getBindGroupLayout ( 0 ) ,
159
+ entries : [
160
+ {
161
+ binding : 0 ,
162
+ resource : texture . createView ( { swizzle : otherSwizzle } ) ,
163
+ } ,
164
+ ] ,
165
+ } ) ;
166
+
167
+ const encoder = t . device . createCommandEncoder ( ) ;
168
+ switch ( pipelineType ) {
169
+ case 'compute' : {
170
+ const pass = encoder . beginComputePass ( ) ;
171
+ pass . setPipeline ( pipeline as GPUComputePipeline ) ;
172
+ pass . setBindGroup ( 0 , bindGroup0 ) ;
173
+ pass . setBindGroup ( 1 , bindGroup1 ) ;
174
+ pass . dispatchWorkgroups ( 1 ) ;
175
+ pass . end ( ) ;
176
+ break ;
177
+ }
178
+ case 'render' : {
179
+ const view = t . createTextureTracked ( {
180
+ size : [ 1 ] ,
181
+ format : 'rgba8unorm' ,
182
+ usage : GPUTextureUsage . RENDER_ATTACHMENT ,
183
+ } ) ;
184
+ const pass = encoder . beginRenderPass ( {
185
+ colorAttachments : [ { view, loadOp : 'clear' , storeOp : 'store' } ] ,
186
+ } ) ;
187
+ pass . setPipeline ( pipeline as GPURenderPipeline ) ;
188
+ pass . setBindGroup ( 0 , bindGroup0 ) ;
189
+ pass . setBindGroup ( 1 , bindGroup1 ) ;
190
+ pass . draw ( 3 ) ;
191
+ pass . end ( ) ;
192
+ }
193
+ }
194
+
195
+ const shouldError = t . isCompatibility && ! swizzlesAreTheSame ( swizzle , otherSwizzle ) ;
196
+
197
+ t . expectValidationError ( ( ) => {
198
+ encoder . finish ( ) ;
199
+ } , shouldError ) ;
200
+ } ) ;
0 commit comments