Skip to content

Refactor create view for texture formats #4196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 30 additions & 47 deletions src/webgpu/api/validation/createView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import {
} from '../../capability_info.js';
import { GPUConst } from '../../constants.js';
import {
kTextureFormatInfo,
kAllTextureFormats,
kFeaturesForFormats,
filterFormatsByFeature,
viewCompatibleDeprecated,
textureFormatsAreViewCompatible,
isDepthTextureFormat,
isStencilTextureFormat,
getBlockInfoForTextureFormat,
isTextureFormatPossiblyUsableAsRenderAttachment,
} from '../../format_info.js';
import { kResourceStates } from '../../gpu_test.js';
import {
Expand All @@ -25,9 +28,9 @@ import {
} from '../../util/texture/base.js';
import { reifyExtent3D } from '../../util/unions.js';

import { ValidationTest } from './validation_test.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js';

export const g = makeTestGroup(ValidationTest);
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest);

const kLevels = 6;

Expand All @@ -48,19 +51,15 @@ g.test('format')
)
.combine('useViewFormatList', [false, true])
)
.beforeAllSubcases(t => {
const { textureFormatFeature, viewFormatFeature } = t.params;
t.selectDeviceOrSkipTestCase([textureFormatFeature, viewFormatFeature]);
})
.fn(t => {
const { textureFormat, viewFormat, useViewFormatList } = t.params;
const { blockWidth, blockHeight } = kTextureFormatInfo[textureFormat];
const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(textureFormat);

t.skipIfTextureFormatNotSupportedDeprecated(textureFormat, viewFormat);
t.skipIfTextureFormatNotSupported(textureFormat, viewFormat);

const compatible =
viewFormat === undefined ||
viewCompatibleDeprecated(t.isCompatibility, textureFormat, viewFormat);
textureFormatsAreViewCompatible(t.device, textureFormat, viewFormat);

const texture = t.createTextureTracked({
format: textureFormat,
Expand Down Expand Up @@ -94,11 +93,9 @@ g.test('dimension')
.combine('textureDimension', kTextureDimensions)
.combine('viewDimension', [...kTextureViewDimensions, undefined])
)
.beforeAllSubcases(t => {
t.skipIfTextureViewDimensionNotSupportedDeprecated(t.params.viewDimension);
})
.fn(t => {
const { textureDimension, viewDimension } = t.params;
t.skipIfTextureViewDimensionNotSupported(t.params.viewDimension);

const size = textureDimension === '1d' ? [4] : [4, 4, 6];
const textureDescriptor = {
Expand Down Expand Up @@ -130,24 +127,22 @@ g.test('aspect')
.combine('format', kAllTextureFormats)
.combine('aspect', kTextureAspects)
)
.beforeAllSubcases(t => {
const { format } = t.params;
t.selectDeviceForTextureFormatOrSkipTestCase(format);
})
.fn(t => {
const { format, aspect } = t.params;
const info = kTextureFormatInfo[format];
const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format);

t.skipIfTextureFormatNotSupported(format);

const texture = t.createTextureTracked({
format,
size: [info.blockWidth, info.blockHeight, 1],
size: [blockWidth, blockHeight, 1],
usage: GPUTextureUsage.TEXTURE_BINDING,
});

const success =
aspect === 'all' ||
(aspect === 'depth-only' && info.depth) ||
(aspect === 'stencil-only' && info.stencil);
(aspect === 'depth-only' && isDepthTextureFormat(format)) ||
(aspect === 'stencil-only' && isStencilTextureFormat(format));
t.expectValidationError(() => {
texture.createView({ aspect });
}, !success);
Expand Down Expand Up @@ -277,7 +272,7 @@ g.test('mip_levels')
const { textureDimension, viewDimension, textureLevels, baseMipLevel, mipLevelCount } =
t.params;

t.skipIfTextureViewDimensionNotSupportedDeprecated(viewDimension);
t.skipIfTextureViewDimensionNotSupported(viewDimension);

const textureDescriptor: GPUTextureDescriptor = {
format: 'rgba8unorm',
Expand Down Expand Up @@ -317,7 +312,7 @@ g.test('cube_faces_square')
.fn(t => {
const { dimension, size } = t.params;

t.skipIfTextureViewDimensionNotSupportedDeprecated(dimension);
t.skipIfTextureViewDimensionNotSupported(dimension);

const texture = t.createTextureTracked({
format: 'rgba8unorm',
Expand Down Expand Up @@ -352,43 +347,31 @@ g.test('texture_view_usage')
.combine('format', kAllTextureFormats)
.combine('textureUsage0', kTextureUsages)
.combine('textureUsage1', kTextureUsages)
.filter(({ format, textureUsage0, textureUsage1 }) => {
const info = kTextureFormatInfo[format];
.unless(({ format, textureUsage0, textureUsage1 }) => {
const textureUsage = textureUsage0 | textureUsage1;

if (
return (
(textureUsage & GPUConst.TextureUsage.RENDER_ATTACHMENT) !== 0 &&
info.color &&
!info.colorRender
) {
return false;
}

return true;
!isTextureFormatPossiblyUsableAsRenderAttachment(format)
);
})
.beginSubcases()
.combine('textureViewUsage0', [0, ...kTextureUsages])
.combine('textureViewUsage1', [0, ...kTextureUsages])
)
.beforeAllSubcases(t => {
const { format, textureUsage0, textureUsage1 } = t.params;
const info = kTextureFormatInfo[format];
const textureUsage = textureUsage0 | textureUsage1;
t.skipIfTextureFormatNotSupportedDeprecated(format);
t.selectDeviceOrSkipTestCase(info.feature);
if (textureUsage & GPUTextureUsage.STORAGE_BINDING) {
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(format);
}
})
.fn(t => {
const { format, textureUsage0, textureUsage1, textureViewUsage0, textureViewUsage1 } = t.params;
const info = kTextureFormatInfo[format];

const size = [info.blockWidth, info.blockHeight, 1];
t.skipIfTextureFormatNotSupported(format);

const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format);

const size = [blockWidth, blockHeight, 1];
const dimension = '2d';
const mipLevelCount = 1;
const usage = textureUsage0 | textureUsage1;

t.skipIfTextureFormatDoesNotSupportUsage(usage, format);

const textureDescriptor: GPUTextureDescriptor = {
size,
mipLevelCount,
Expand Down
26 changes: 24 additions & 2 deletions src/webgpu/format_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,19 @@ export function getBlockInfoForColorTextureFormat(format: ColorTextureFormat) {
};
}

/**
* Gets the block width, height, and bytes per block for a color texture format.
* Note that bytesPerBlock will be undefined if format's size is undefined.
*/
export function getBlockInfoForTextureFormat(format: GPUTextureFormat) {
const info = kTextureFormatInfo[format];
return {
blockWidth: info.blockWidth,
blockHeight: info.blockHeight,
bytesPerBlock: info.color?.bytes ?? info.depth?.bytes ?? info.stencil?.bytes,
};
}

/**
* Gets the baseFormat for a texture format.
*/
Expand Down Expand Up @@ -1863,6 +1876,15 @@ export function isTextureFormatColorRenderable(
return !!kAllTextureFormatInfo[format].colorRender;
}

/**
* Returns true if a texture can possibly be used as a render attachment.
* The texture may require certain features to be enabled.
*/
export function isTextureFormatPossiblyUsableAsRenderAttachment(format: GPUTextureFormat) {
const info = kTextureFormatInfo[format];
return format === 'rg11b10ufloat' || isDepthOrStencilTextureFormat(format) || !!info.colorRender;
}

export function is16Float(format: GPUTextureFormat) {
return format === 'r16float' || format === 'rg16float' || format === 'rgba16float';
}
Expand Down Expand Up @@ -1941,7 +1963,7 @@ export function isSintOrUintFormat(format: GPUTextureFormat) {
}

/**
* Returns true of format can be multisampled.
* Returns true if format can be multisampled.
*/
export const kCompatModeUnsupportedMultisampledTextureFormats: readonly GPUTextureFormat[] = [
'r8uint',
Expand Down Expand Up @@ -1990,7 +2012,7 @@ export function isTextureFormatMultisampled(device: GPUDevice, format: GPUTextur
}

/**
* Returns true of a texture can be "resolved". uint/sint formats can be multisampled but
* Returns true if a texture can be "resolved". uint/sint formats can be multisampled but
* can not be resolved.
*/
export function isTextureFormatResolvable(device: GPUDevice, format: GPUTextureFormat): boolean {
Expand Down
26 changes: 25 additions & 1 deletion src/webgpu/gpu_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
isTextureFormatUsableAsStorageFormatDeprecated,
isMultisampledTextureFormatDeprecated,
isTextureFormatUsableAsStorageFormat,
isTextureFormatUsableAsRenderAttachment,
} from './format_info.js';
import { checkElementsEqual, checkElementsBetween } from './util/check_contents.js';
import { CommandBufferMaker, EncoderType } from './util/command_buffer_maker.js';
Expand Down Expand Up @@ -608,6 +609,29 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
}
}

skipIfTextureFormatNotUsableAsRenderAttachment(...formats: (GPUTextureFormat | undefined)[]) {
for (const format of formats) {
if (format && !isTextureFormatUsableAsRenderAttachment(this.device, format)) {
this.skip(`Texture with ${format} is not usable as a render attachment`);
}
}
}

skipIfTextureFormatDoesNotSupportUsage(
usage: GPUTextureUsageFlags,
...formats: (GPUTextureFormat | undefined)[]
) {
for (const format of formats) {
if (!format) continue;
if (usage & GPUTextureUsage.RENDER_ATTACHMENT) {
this.skipIfTextureFormatNotUsableAsRenderAttachment(format);
}
if (usage & GPUTextureUsage.STORAGE_BINDING) {
this.skipIfTextureFormatNotUsableAsStorageTexture(format);
}
}
}

/** Skips this test case if the `langFeature` is *not* supported. */
skipIfLanguageFeatureNotSupported(langFeature: WGSLLanguageFeature) {
if (!this.hasLanguageFeature(langFeature)) {
Expand All @@ -622,7 +646,7 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
}
}

/** returns true iff the `langFeature` is supported */
/** returns true if the `langFeature` is supported */
hasLanguageFeature(langFeature: WGSLLanguageFeature) {
const lf = getGPU(this.rec).wgslLanguageFeatures;
return lf !== undefined && lf.has(langFeature);
Expand Down