Skip to content

Commit 672773a

Browse files
authored
Plan api,operation,memory_sync,texture,* (gpuweb#954)
* Plan api,operation,memory_sync,texture,* * Address review feedback * formatting
1 parent 45cfcef commit 672773a

File tree

3 files changed

+243
-2
lines changed

3 files changed

+243
-2
lines changed
Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,72 @@
11
export const description = `
22
Memory Synchronization Tests for Texture: read before write and read after write.
33
4-
TODO
4+
- TODO: Test synchronization between multiple queues.
55
`;
66

77
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
88
import { GPUTest } from '../../../../gpu_test.js';
99

10+
import {
11+
kOperationBoundaries,
12+
kBoundaryInfo,
13+
kAllReadOps,
14+
kAllWriteOps,
15+
checkOpsValidForContext,
16+
} from './texture_sync_test.js';
17+
1018
export const g = makeTestGroup(GPUTest);
19+
20+
g.test('rw')
21+
.desc(
22+
`
23+
Perform a 'read' operations on a texture, followed by a 'write' operation.
24+
Operations are separated by a 'boundary' (pass, encoder, queue-op, etc.).
25+
Test that the results are synchronized.
26+
The read should not see the contents written by the subsequent write.`
27+
)
28+
.params(u =>
29+
u
30+
.combine('boundary', kOperationBoundaries)
31+
.expand('_context', p => kBoundaryInfo[p.boundary].contexts)
32+
.expandWithParams(function* ({ _context }) {
33+
for (const read of kAllReadOps) {
34+
for (const write of kAllWriteOps) {
35+
if (checkOpsValidForContext([read, write], _context)) {
36+
yield {
37+
write: { op: write, in: _context[0] },
38+
read: { op: read, in: _context[1] },
39+
};
40+
}
41+
}
42+
}
43+
})
44+
)
45+
.unimplemented();
46+
47+
g.test('wr')
48+
.desc(
49+
`
50+
Perform a 'write' operation on a texture, followed by a 'read' operation.
51+
Operations are separated by a 'boundary' (pass, encoder, queue-op, etc.).
52+
Test that the results are synchronized.
53+
The read should see exactly the contents written by the previous write.`
54+
)
55+
.params(u =>
56+
u
57+
.combine('boundary', kOperationBoundaries)
58+
.expand('_context', p => kBoundaryInfo[p.boundary].contexts)
59+
.expandWithParams(function* ({ _context }) {
60+
for (const read of kAllReadOps) {
61+
for (const write of kAllWriteOps) {
62+
if (checkOpsValidForContext([write, read], _context)) {
63+
yield {
64+
read: { op: read, in: _context[0] },
65+
write: { op: write, in: _context[1] },
66+
};
67+
}
68+
}
69+
}
70+
})
71+
)
72+
.unimplemented();
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Boundary between the first operation, and the second operation.
3+
*/
4+
export const kOperationBoundaries = [
5+
'queue-op', // Operations are performed in different queue operations (submit, writeTexture).
6+
'command-buffer', // Operations are in different command buffers.
7+
'pass', // Operations are in different passes.
8+
'render-bundle', // Operations are in different render bundles.
9+
'dispatch', // Operations are in different dispatches.
10+
'draw', // Operations are in different draws.
11+
] as const;
12+
export type OperationBoundary = typeof kOperationBoundaries[number];
13+
14+
/**
15+
* Context a particular operation is permitted in.
16+
*/
17+
export const kOperationContexts = [
18+
'queue', // Operation occurs on the GPUQueue object
19+
'command-encoder', // Operation may be encoded in a GPUCommandEncoder.
20+
'compute-pass-encoder', // Operation may be encoded in a GPUComputePassEncoder.
21+
'render-pass-encoder', // Operation may be encoded in a GPURenderPassEncoder.
22+
'render-bundle-encoder', // Operation may be encoded in a GPURenderBundleEncoder.
23+
] as const;
24+
export type OperationContext = typeof kOperationContexts[number];
25+
26+
interface BoundaryInfo {
27+
readonly contexts: [OperationContext, OperationContext][];
28+
// Add fields as needed
29+
}
30+
31+
function combineContexts(
32+
as: readonly OperationContext[],
33+
bs: readonly OperationContext[]
34+
): [OperationContext, OperationContext][] {
35+
const result: [OperationContext, OperationContext][] = [];
36+
for (const a of as) {
37+
for (const b of bs) {
38+
result.push([a, b]);
39+
}
40+
}
41+
return result;
42+
}
43+
44+
const queueContexts = combineContexts(kOperationContexts, kOperationContexts);
45+
const commandBufferContexts = combineContexts(
46+
kOperationContexts.filter(c => c !== 'queue'),
47+
kOperationContexts.filter(c => c !== 'queue')
48+
);
49+
50+
/**
51+
* Mapping of OperationBoundary => to a set of OperationContext pairs.
52+
* The boundary is capable of separating operations in those two contexts.
53+
*/
54+
export const kBoundaryInfo: {
55+
readonly [k in OperationBoundary]: BoundaryInfo;
56+
} = /* prettier-ignore */ {
57+
'queue-op': {
58+
contexts: queueContexts,
59+
},
60+
'command-buffer': {
61+
contexts: commandBufferContexts,
62+
},
63+
'pass': {
64+
contexts: [
65+
['compute-pass-encoder', 'compute-pass-encoder'],
66+
['compute-pass-encoder', 'render-pass-encoder'],
67+
['render-pass-encoder', 'compute-pass-encoder'],
68+
['render-pass-encoder', 'render-pass-encoder'],
69+
['render-bundle-encoder', 'render-pass-encoder'],
70+
['render-pass-encoder', 'render-bundle-encoder'],
71+
['render-bundle-encoder', 'render-bundle-encoder'],
72+
],
73+
},
74+
'render-bundle': {
75+
contexts: [
76+
['render-bundle-encoder', 'render-pass-encoder'],
77+
['render-pass-encoder', 'render-bundle-encoder'],
78+
['render-bundle-encoder', 'render-bundle-encoder'],
79+
],
80+
},
81+
'dispatch': {
82+
contexts: [
83+
['compute-pass-encoder', 'compute-pass-encoder'],
84+
],
85+
},
86+
'draw': {
87+
contexts: [
88+
['render-pass-encoder', 'render-pass-encoder'],
89+
['render-bundle-encoder', 'render-pass-encoder'],
90+
],
91+
},
92+
};
93+
94+
export const kAllWriteOps = [
95+
'write-texture',
96+
'b2t-copy',
97+
't2t-copy',
98+
'storage',
99+
'attachment-store',
100+
'attachment-resolve',
101+
] as const;
102+
export type WriteOp = typeof kAllWriteOps[number];
103+
104+
export const kAllReadOps = [
105+
't2b-copy',
106+
't2t-copy',
107+
'attachment-load',
108+
'storage',
109+
'sample',
110+
] as const;
111+
export type ReadOp = typeof kAllReadOps[number];
112+
113+
export type Op = ReadOp | WriteOp;
114+
115+
interface OpInfo {
116+
readonly contexts: OperationContext[];
117+
// Add fields as needed
118+
}
119+
120+
/**
121+
* Mapping of Op to the OperationContext(s) it is valid in
122+
*/
123+
const kOpInfo: {
124+
readonly [k in Op]: OpInfo;
125+
} = /* prettier-ignore */ {
126+
'write-texture': { contexts: [ 'queue' ] },
127+
'b2t-copy': { contexts: [ 'command-encoder' ] },
128+
't2t-copy': { contexts: [ 'command-encoder' ] },
129+
't2b-copy': { contexts: [ 'command-encoder' ] },
130+
'storage': { contexts: [ 'compute-pass-encoder', 'render-pass-encoder', 'render-bundle-encoder' ] },
131+
'sample': { contexts: [ 'compute-pass-encoder', 'render-pass-encoder', 'render-bundle-encoder' ] },
132+
'attachment-store': { contexts: [ 'render-pass-encoder' ] },
133+
'attachment-resolve': { contexts: [ 'render-pass-encoder' ] },
134+
'attachment-load': { contexts: [ 'render-pass-encoder' ] },
135+
};
136+
137+
export function checkOpsValidForContext(
138+
ops: [Op, Op],
139+
context: [OperationContext, OperationContext]
140+
) {
141+
return (
142+
kOpInfo[ops[0]].contexts.indexOf(context[0]) !== -1 &&
143+
kOpInfo[ops[1]].contexts.indexOf(context[1]) !== -1
144+
);
145+
}
Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,44 @@
11
export const description = `
22
Memory Synchronization Tests for Texture: write after write.
33
4-
TODO
4+
- TODO: Test synchronization between multiple queues.
55
`;
66

77
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
88
import { GPUTest } from '../../../../gpu_test.js';
99

10+
import {
11+
kOperationBoundaries,
12+
kBoundaryInfo,
13+
kAllWriteOps,
14+
checkOpsValidForContext,
15+
} from './texture_sync_test.js';
16+
1017
export const g = makeTestGroup(GPUTest);
18+
19+
g.test('ww')
20+
.desc(
21+
`
22+
Perform a 'first' write operation on a texture, followed by a 'second' write operation.
23+
Operations are separated by a 'boundary' (pass, encoder, queue-op, etc.).
24+
Test that the results are synchronized.
25+
If overlapping, the second write should overwrite the contents of the first.`
26+
)
27+
.params(u =>
28+
u
29+
.combine('boundary', kOperationBoundaries)
30+
.expand('_context', p => kBoundaryInfo[p.boundary].contexts)
31+
.expandWithParams(function* ({ _context }) {
32+
for (const first of kAllWriteOps) {
33+
for (const second of kAllWriteOps) {
34+
if (checkOpsValidForContext([first, second], _context)) {
35+
yield {
36+
first: { op: first, in: _context[0] },
37+
second: { op: second, in: _context[1] },
38+
};
39+
}
40+
}
41+
}
42+
})
43+
)
44+
.unimplemented();

0 commit comments

Comments
 (0)