Skip to content

Commit

Permalink
op: Implement 'mipmapFilter' test in filter_mode.spec.ts
Browse files Browse the repository at this point in the history
This PR adds a new test to test that mipmapFilter affects drawing the
slanted plane with different filter modes.

Issue: #2070
  • Loading branch information
Gyuyoung committed Dec 23, 2022
1 parent 44173ed commit 13d9899
Showing 1 changed file with 167 additions and 1 deletion.
168 changes: 167 additions & 1 deletion src/webgpu/api/operation/sampling/filter_mode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,172 @@ TODO:
`;

import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert } from '../../../../common/util/util.js';
import { GPUTest } from '../../../gpu_test.js';

export const g = makeTestGroup(GPUTest);
const kRTSize = 16;
const xMiddle = kRTSize / 2; // we check the pixel value in the middle of the render target
const kColorAttachmentFormat = 'rgba8unorm';
const colors = [
new Uint8Array([0xff, 0x00, 0x00, 0xff]), // miplevel = 0
new Uint8Array([0x00, 0xff, 0x00, 0xff]), // miplevel = 1
new Uint8Array([0x00, 0x00, 0xff, 0xff]), // miplevel = 2
];

class SamplerFilterModeSlantedPlaneTest extends GPUTest {
private pipeline: GPURenderPipeline | undefined;
async init(): Promise<void> {
await super.init();

this.pipeline = this.device.createRenderPipeline({
layout: 'auto',
vertex: {
module: this.device.createShaderModule({
code: `
struct Outputs {
@builtin(position) Position : vec4<f32>,
@location(0) fragUV : vec2<f32>,
};
@vertex fn main(
@builtin(vertex_index) VertexIndex : u32) -> Outputs {
var position : array<vec3<f32>, 6> = array<vec3<f32>, 6>(
vec3<f32>(-0.5, 0.5, -0.5),
vec3<f32>(0.5, 0.5, -0.5),
vec3<f32>(-0.5, 0.5, 0.5),
vec3<f32>(-0.5, 0.5, 0.5),
vec3<f32>(0.5, 0.5, -0.5),
vec3<f32>(0.5, 0.5, 0.5));
// uv is pre-scaled to mimic repeating tiled texture
var uv : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
vec2<f32>(0.0, 0.0),
vec2<f32>(1.0, 0.0),
vec2<f32>(0.0, 50.0),
vec2<f32>(0.0, 50.0),
vec2<f32>(1.0, 0.0),
vec2<f32>(1.0, 50.0));
// draw a slanted plane in a specific way
let matrix : mat4x4<f32> = mat4x4<f32>(
vec4<f32>(-1.7320507764816284, 1.8322050568049563e-16, -6.176817699518044e-17, -6.170640314703498e-17),
vec4<f32>(-2.1211504944260596e-16, -1.496108889579773, 0.5043753981590271, 0.5038710236549377),
vec4<f32>(0.0, -43.63650894165039, -43.232173919677734, -43.18894577026367),
vec4<f32>(0.0, 21.693578720092773, 21.789791107177734, 21.86800193786621));
var output : Outputs;
output.fragUV = uv[VertexIndex];
output.Position = matrix * vec4<f32>(position[VertexIndex], 1.0);
return output;
}
`,
}),
entryPoint: 'main',
},
fragment: {
module: this.device.createShaderModule({
code: `
@group(0) @binding(0) var sampler0 : sampler;
@group(0) @binding(1) var texture0 : texture_2d<f32>;
@fragment fn main(
@builtin(position) FragCoord : vec4<f32>,
@location(0) fragUV: vec2<f32>)
-> @location(0) vec4<f32> {
return textureSample(texture0, sampler0, fragUV);
}
`,
}),
entryPoint: 'main',
targets: [{ format: 'rgba8unorm' }],
},
primitive: { topology: 'triangle-list' },
});
}

// return the render target texture object
drawSlantedPlane(textureView: GPUTextureView, sampler: GPUSampler): GPUTexture {
// make sure it's already initialized
assert(this.pipeline !== undefined);

const bindGroup = this.device.createBindGroup({
entries: [
{ binding: 0, resource: sampler },
{ binding: 1, resource: textureView },
],
layout: this.pipeline.getBindGroupLayout(0),
});

const colorAttachment = this.device.createTexture({
format: kColorAttachmentFormat,
size: { width: kRTSize, height: kRTSize, depthOrArrayLayers: 1 },
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
});
const colorAttachmentView = colorAttachment.createView();

const encoder = this.device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [
{
view: colorAttachmentView,
storeOp: 'store',
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
},
],
});
pass.setPipeline(this.pipeline);
pass.setBindGroup(0, bindGroup);
pass.draw(6);
pass.end();
this.device.queue.submit([encoder.finish()]);

return colorAttachment;
}
}

export const g = makeTestGroup(SamplerFilterModeSlantedPlaneTest);

g.test('mipmapFilter')
.desc('Test that mipmapFilter affects drawing the slanted plane with different filter modes.')
.params(u =>
u //
.combine('mipmapFilter', ['linear', 'nearest'] as const)
.combineWithParams([
{
results: [
{ coord: { x: xMiddle, y: 2 }, expected: colors[2] },
{ coord: { x: xMiddle, y: 6 }, expected: [colors[0], colors[1]] },
],
},
])
)
.fn(async t => {
const { mipmapFilter } = t.params;

const texture = t.createTexture2DWithMipmaps(colors);
const textureView = texture.createView();

const sampler = t.device.createSampler({
mipmapFilter,
});

const colorAttachment = t.drawSlantedPlane(textureView, sampler);

for (const entry of t.params.results) {
if (entry.expected instanceof Uint8Array) {
// equal exactly one color
t.expectSinglePixelIn2DTexture(colorAttachment, kColorAttachmentFormat, entry.coord, {
exp: entry.expected,
});
} else {
// a lerp between two colors
t.expectSinglePixelBetweenTwoValuesIn2DTexture(
colorAttachment,
kColorAttachmentFormat,
entry.coord,
{
exp: entry.expected as [Uint8Array, Uint8Array],
}
);
}
}
});

0 comments on commit 13d9899

Please sign in to comment.