1export const description = ` 2copyBufferToBuffer tests. 3 4Test Plan: 5* Buffer is valid/invalid 6 - the source buffer is invalid 7 - the destination buffer is invalid 8* Buffer usages 9 - the source buffer is created without GPUBufferUsage::COPY_SRC 10 - the destination buffer is created without GPUBufferUsage::COPY_DEST 11* CopySize 12 - copySize is not a multiple of 4 13 - copySize is 0 14* copy offsets 15 - sourceOffset is not a multiple of 4 16 - destinationOffset is not a multiple of 4 17* Arthimetic overflow 18 - (sourceOffset + copySize) is overflow 19 - (destinationOffset + copySize) is overflow 20* Out of bounds 21 - (sourceOffset + copySize) > size of source buffer 22 - (destinationOffset + copySize) > size of destination buffer 23* Source buffer and destination buffer are the same buffer 24`; 25 26import { poptions, params } from '../../../common/framework/params_builder.js'; 27import { makeTestGroup } from '../../../common/framework/test_group.js'; 28import { kBufferUsages } from '../../capability_info.js'; 29import { kMaxSafeMultipleOf8 } from '../../util/math.js'; 30 31import { ValidationTest } from './validation_test.js'; 32 33class F extends ValidationTest { 34 TestCopyBufferToBuffer(options: { 35 srcBuffer: GPUBuffer; 36 srcOffset: number; 37 dstBuffer: GPUBuffer; 38 dstOffset: number; 39 copySize: number; 40 isSuccess: boolean; 41 }): void { 42 const { srcBuffer, srcOffset, dstBuffer, dstOffset, copySize, isSuccess } = options; 43 44 const commandEncoder = this.device.createCommandEncoder(); 45 commandEncoder.copyBufferToBuffer(srcBuffer, srcOffset, dstBuffer, dstOffset, copySize); 46 47 this.expectValidationError(() => { 48 commandEncoder.finish(); 49 }, !isSuccess); 50 } 51} 52 53export const g = makeTestGroup(F); 54 55g.test('copy_with_invalid_buffer').fn(async t => { 56 const validBuffer = t.device.createBuffer({ 57 size: 16, 58 usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, 59 }); 60 61 const errorBuffer = t.getErrorBuffer(); 62 63 t.TestCopyBufferToBuffer({ 64 srcBuffer: errorBuffer, 65 srcOffset: 0, 66 dstBuffer: validBuffer, 67 dstOffset: 0, 68 copySize: 8, 69 isSuccess: false, 70 }); 71 72 t.TestCopyBufferToBuffer({ 73 srcBuffer: validBuffer, 74 srcOffset: 0, 75 dstBuffer: errorBuffer, 76 dstOffset: 0, 77 copySize: 8, 78 isSuccess: false, 79 }); 80}); 81 82g.test('buffer_usage') 83 .params( 84 params() 85 .combine(poptions('srcUsage', kBufferUsages)) 86 .combine(poptions('dstUsage', kBufferUsages)) 87 ) 88 .fn(async t => { 89 const { srcUsage, dstUsage } = t.params; 90 91 const srcBuffer = t.device.createBuffer({ 92 size: 16, 93 usage: srcUsage, 94 }); 95 const dstBuffer = t.device.createBuffer({ 96 size: 16, 97 usage: dstUsage, 98 }); 99 100 const isSuccess = srcUsage === GPUBufferUsage.COPY_SRC && dstUsage === GPUBufferUsage.COPY_DST; 101 102 t.TestCopyBufferToBuffer({ 103 srcBuffer, 104 srcOffset: 0, 105 dstBuffer, 106 dstOffset: 0, 107 copySize: 8, 108 isSuccess, 109 }); 110 }); 111 112g.test('copy_size_alignment') 113 .params([ 114 { copySize: 0, _isSuccess: true }, 115 { copySize: 2, _isSuccess: false }, 116 { copySize: 4, _isSuccess: true }, 117 { copySize: 5, _isSuccess: false }, 118 { copySize: 8, _isSuccess: true }, 119 ] as const) 120 .fn(async t => { 121 const { copySize, _isSuccess: isSuccess } = t.params; 122 123 const srcBuffer = t.device.createBuffer({ 124 size: 16, 125 usage: GPUBufferUsage.COPY_SRC, 126 }); 127 const dstBuffer = t.device.createBuffer({ 128 size: 16, 129 usage: GPUBufferUsage.COPY_DST, 130 }); 131 132 t.TestCopyBufferToBuffer({ 133 srcBuffer, 134 srcOffset: 0, 135 dstBuffer, 136 dstOffset: 0, 137 copySize, 138 isSuccess, 139 }); 140 }); 141 142g.test('copy_offset_alignment') 143 .params([ 144 { srcOffset: 0, dstOffset: 0, _isSuccess: true }, 145 { srcOffset: 2, dstOffset: 0, _isSuccess: false }, 146 { srcOffset: 4, dstOffset: 0, _isSuccess: true }, 147 { srcOffset: 5, dstOffset: 0, _isSuccess: false }, 148 { srcOffset: 8, dstOffset: 0, _isSuccess: true }, 149 { srcOffset: 0, dstOffset: 2, _isSuccess: false }, 150 { srcOffset: 0, dstOffset: 4, _isSuccess: true }, 151 { srcOffset: 0, dstOffset: 5, _isSuccess: false }, 152 { srcOffset: 0, dstOffset: 8, _isSuccess: true }, 153 { srcOffset: 4, dstOffset: 4, _isSuccess: true }, 154 ] as const) 155 .fn(async t => { 156 const { srcOffset, dstOffset, _isSuccess: isSuccess } = t.params; 157 158 const srcBuffer = t.device.createBuffer({ 159 size: 16, 160 usage: GPUBufferUsage.COPY_SRC, 161 }); 162 const dstBuffer = t.device.createBuffer({ 163 size: 16, 164 usage: GPUBufferUsage.COPY_DST, 165 }); 166 167 t.TestCopyBufferToBuffer({ 168 srcBuffer, 169 srcOffset, 170 dstBuffer, 171 dstOffset, 172 copySize: 8, 173 isSuccess, 174 }); 175 }); 176 177g.test('copy_overflow') 178 .params([ 179 { srcOffset: 0, dstOffset: 0, copySize: kMaxSafeMultipleOf8 }, 180 { srcOffset: 16, dstOffset: 0, copySize: kMaxSafeMultipleOf8 }, 181 { srcOffset: 0, dstOffset: 16, copySize: kMaxSafeMultipleOf8 }, 182 { srcOffset: kMaxSafeMultipleOf8, dstOffset: 0, copySize: 16 }, 183 { srcOffset: 0, dstOffset: kMaxSafeMultipleOf8, copySize: 16 }, 184 { srcOffset: kMaxSafeMultipleOf8, dstOffset: 0, copySize: kMaxSafeMultipleOf8 }, 185 { srcOffset: 0, dstOffset: kMaxSafeMultipleOf8, copySize: kMaxSafeMultipleOf8 }, 186 { 187 srcOffset: kMaxSafeMultipleOf8, 188 dstOffset: kMaxSafeMultipleOf8, 189 copySize: kMaxSafeMultipleOf8, 190 }, 191 ] as const) 192 .fn(async t => { 193 const { srcOffset, dstOffset, copySize } = t.params; 194 195 const srcBuffer = t.device.createBuffer({ 196 size: 16, 197 usage: GPUBufferUsage.COPY_SRC, 198 }); 199 const dstBuffer = t.device.createBuffer({ 200 size: 16, 201 usage: GPUBufferUsage.COPY_DST, 202 }); 203 204 t.TestCopyBufferToBuffer({ 205 srcBuffer, 206 srcOffset, 207 dstBuffer, 208 dstOffset, 209 copySize, 210 isSuccess: false, 211 }); 212 }); 213 214g.test('copy_out_of_bounds') 215 .params([ 216 { srcOffset: 0, dstOffset: 0, copySize: 32, _isSuccess: true }, 217 { srcOffset: 0, dstOffset: 0, copySize: 36 }, 218 { srcOffset: 36, dstOffset: 0, copySize: 4 }, 219 { srcOffset: 0, dstOffset: 36, copySize: 4 }, 220 { srcOffset: 36, dstOffset: 0, copySize: 0 }, 221 { srcOffset: 0, dstOffset: 36, copySize: 0 }, 222 { srcOffset: 20, dstOffset: 0, copySize: 16 }, 223 { srcOffset: 20, dstOffset: 0, copySize: 12, _isSuccess: true }, 224 { srcOffset: 0, dstOffset: 20, copySize: 16 }, 225 { srcOffset: 0, dstOffset: 20, copySize: 12, _isSuccess: true }, 226 ] as const) 227 .fn(async t => { 228 const { srcOffset, dstOffset, copySize, _isSuccess = false } = t.params; 229 230 const srcBuffer = t.device.createBuffer({ 231 size: 32, 232 usage: GPUBufferUsage.COPY_SRC, 233 }); 234 const dstBuffer = t.device.createBuffer({ 235 size: 32, 236 usage: GPUBufferUsage.COPY_DST, 237 }); 238 239 t.TestCopyBufferToBuffer({ 240 srcBuffer, 241 srcOffset, 242 dstBuffer, 243 dstOffset, 244 copySize, 245 isSuccess: _isSuccess, 246 }); 247 }); 248 249g.test('copy_within_same_buffer') 250 .params([ 251 { srcOffset: 0, dstOffset: 8, copySize: 4 }, 252 { srcOffset: 8, dstOffset: 0, copySize: 4 }, 253 { srcOffset: 0, dstOffset: 4, copySize: 8 }, 254 { srcOffset: 4, dstOffset: 0, copySize: 8 }, 255 ] as const) 256 .fn(async t => { 257 const { srcOffset, dstOffset, copySize } = t.params; 258 259 const buffer = t.device.createBuffer({ 260 size: 16, 261 usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, 262 }); 263 264 t.TestCopyBufferToBuffer({ 265 srcBuffer: buffer, 266 srcOffset, 267 dstBuffer: buffer, 268 dstOffset, 269 copySize, 270 isSuccess: false, 271 }); 272 }); 273