Implement initialization of multisampled textures
Metal needs RenderTarget usage to be added to the texture allocation so the clear can be done using a render pass. Already working for GL which does not have usage flags on creation. Also working on Vulkan which does not need a render pass. We use vkCmdClearColorImage. D3D12 also needs a render pass to clear multisampled textures, but it already requires multisampled textures to be created with RenderTarget flags. To test the behavior, NonzeroTextureCreation tests are expanded, and the ExpectSampledDepthData helper is factored into a more general ExpectSampledFloatData helper. Fixes: dawn:794 Change-Id: If0f9f26f3c58b4292c85265aa7ff330e9931ddae Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/55604 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
2a57db73cb
commit
75c5067ed1
|
@ -471,6 +471,9 @@ namespace dawn_native { namespace d3d12 {
|
|||
mDxgiKeyedMutex = std::move(dxgiKeyedMutex);
|
||||
mSwapChainTexture = isSwapChainTexture;
|
||||
|
||||
D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc();
|
||||
mD3D12ResourceFlags = desc.Flags;
|
||||
|
||||
AllocationInfo info;
|
||||
info.mMethod = AllocationMethod::kExternal;
|
||||
// When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the
|
||||
|
@ -507,6 +510,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
resourceDescriptor.Flags =
|
||||
D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture());
|
||||
mD3D12ResourceFlags = resourceDescriptor.Flags;
|
||||
|
||||
DAWN_TRY_ASSIGN(mResourceAllocation,
|
||||
ToBackend(GetDevice())
|
||||
|
@ -879,82 +883,80 @@ namespace dawn_native { namespace d3d12 {
|
|||
uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
|
||||
float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
|
||||
|
||||
if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0) {
|
||||
if (GetFormat().HasDepthOrStencil()) {
|
||||
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
|
||||
if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0) {
|
||||
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
|
||||
|
||||
for (uint32_t level = range.baseMipLevel;
|
||||
level < range.baseMipLevel + range.levelCount; ++level) {
|
||||
for (uint32_t layer = range.baseArrayLayer;
|
||||
layer < range.baseArrayLayer + range.layerCount; ++layer) {
|
||||
// Iterate the aspects individually to determine which clear flags to use.
|
||||
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||
for (Aspect aspect : IterateEnumMask(range.aspects)) {
|
||||
if (clearValue == TextureBase::ClearValue::Zero &&
|
||||
IsSubresourceContentInitialized(
|
||||
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
|
||||
// Skip lazy clears if already initialized.
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (aspect) {
|
||||
case Aspect::Depth:
|
||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||
break;
|
||||
case Aspect::Stencil:
|
||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
if (clearFlags == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CPUDescriptorHeapAllocation dsvHandle;
|
||||
DAWN_TRY_ASSIGN(dsvHandle, device->GetDepthStencilViewAllocator()
|
||||
->AllocateTransientCPUDescriptors());
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor =
|
||||
dsvHandle.GetBaseDescriptor();
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
|
||||
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
|
||||
&dsvDesc, baseDescriptor);
|
||||
|
||||
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
|
||||
clearColor, 0, nullptr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
range);
|
||||
|
||||
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
|
||||
fClearColor};
|
||||
|
||||
ASSERT(range.aspects == Aspect::Color);
|
||||
for (uint32_t level = range.baseMipLevel;
|
||||
level < range.baseMipLevel + range.levelCount; ++level) {
|
||||
for (uint32_t layer = range.baseArrayLayer;
|
||||
layer < range.baseArrayLayer + range.layerCount; ++layer) {
|
||||
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
|
||||
++level) {
|
||||
for (uint32_t layer = range.baseArrayLayer;
|
||||
layer < range.baseArrayLayer + range.layerCount; ++layer) {
|
||||
// Iterate the aspects individually to determine which clear flags to use.
|
||||
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||
for (Aspect aspect : IterateEnumMask(range.aspects)) {
|
||||
if (clearValue == TextureBase::ClearValue::Zero &&
|
||||
IsSubresourceContentInitialized(
|
||||
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
|
||||
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
|
||||
// Skip lazy clears if already initialized.
|
||||
continue;
|
||||
}
|
||||
|
||||
CPUDescriptorHeapAllocation rtvHeap;
|
||||
DAWN_TRY_ASSIGN(rtvHeap, device->GetRenderTargetViewAllocator()
|
||||
->AllocateTransientCPUDescriptors());
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor();
|
||||
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
|
||||
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(),
|
||||
&rtvDesc, rtvHandle);
|
||||
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
|
||||
switch (aspect) {
|
||||
case Aspect::Depth:
|
||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||
break;
|
||||
case Aspect::Stencil:
|
||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
if (clearFlags == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CPUDescriptorHeapAllocation dsvHandle;
|
||||
DAWN_TRY_ASSIGN(
|
||||
dsvHandle,
|
||||
device->GetDepthStencilViewAllocator()->AllocateTransientCPUDescriptors());
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor =
|
||||
dsvHandle.GetBaseDescriptor();
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
|
||||
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), &dsvDesc,
|
||||
baseDescriptor);
|
||||
|
||||
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
|
||||
clearColor, 0, nullptr);
|
||||
}
|
||||
}
|
||||
} else if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0) {
|
||||
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET, range);
|
||||
|
||||
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor, fClearColor};
|
||||
|
||||
ASSERT(range.aspects == Aspect::Color);
|
||||
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
|
||||
++level) {
|
||||
for (uint32_t layer = range.baseArrayLayer;
|
||||
layer < range.baseArrayLayer + range.layerCount; ++layer) {
|
||||
if (clearValue == TextureBase::ClearValue::Zero &&
|
||||
IsSubresourceContentInitialized(
|
||||
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
|
||||
// Skip lazy clears if already initialized.
|
||||
continue;
|
||||
}
|
||||
|
||||
CPUDescriptorHeapAllocation rtvHeap;
|
||||
DAWN_TRY_ASSIGN(
|
||||
rtvHeap,
|
||||
device->GetRenderTargetViewAllocator()->AllocateTransientCPUDescriptors());
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor();
|
||||
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
|
||||
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
|
||||
rtvHandle);
|
||||
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -123,6 +123,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
ResourceHeapAllocation mResourceAllocation;
|
||||
bool mSwapChainTexture = false;
|
||||
D3D12_RESOURCE_FLAGS mD3D12ResourceFlags;
|
||||
|
||||
ExternalMutexSerial mAcquireMutexKey = ExternalMutexSerial(0);
|
||||
ExternalMutexSerial mReleaseMutexKey = ExternalMutexSerial(0);
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace dawn_native { namespace metal {
|
|||
TextureBase::ClearValue clearValue);
|
||||
|
||||
NSPRef<id<MTLTexture>> mMtlTexture;
|
||||
MTLTextureUsage mMtlUsage;
|
||||
};
|
||||
|
||||
class TextureView final : public TextureViewBase {
|
||||
|
|
|
@ -34,7 +34,9 @@ namespace dawn_native { namespace metal {
|
|||
return usage & kUsageNeedsTextureView;
|
||||
}
|
||||
|
||||
MTLTextureUsage MetalTextureUsage(const Format& format, wgpu::TextureUsage usage) {
|
||||
MTLTextureUsage MetalTextureUsage(const Format& format,
|
||||
wgpu::TextureUsage usage,
|
||||
uint32_t sampleCount) {
|
||||
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
|
||||
|
||||
if (usage & (wgpu::TextureUsage::Storage)) {
|
||||
|
@ -53,7 +55,8 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
if (usage & (wgpu::TextureUsage::RenderAttachment)) {
|
||||
// MTLTextureUsageRenderTarget is needed to clear multisample textures.
|
||||
if (usage & (wgpu::TextureUsage::RenderAttachment) || sampleCount > 1) {
|
||||
result |= MTLTextureUsageRenderTarget;
|
||||
}
|
||||
|
||||
|
@ -310,7 +313,7 @@ namespace dawn_native { namespace metal {
|
|||
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
|
||||
// reinterpretation.
|
||||
mtlDesc.usage = MetalTextureUsage(device->GetValidInternalFormat(descriptor->format),
|
||||
descriptor->usage);
|
||||
descriptor->usage, descriptor->sampleCount);
|
||||
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
|
||||
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
|
||||
mtlDesc.storageMode = MTLStorageModePrivate;
|
||||
|
@ -357,6 +360,7 @@ namespace dawn_native { namespace metal {
|
|||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
|
||||
mMtlTexture =
|
||||
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
|
||||
mMtlUsage = [*mtlDesc usage];
|
||||
|
||||
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
|
||||
device->ConsumedError(ClearTexture(device->GetPendingCommandContext(),
|
||||
|
@ -370,6 +374,8 @@ namespace dawn_native { namespace metal {
|
|||
NSPRef<id<MTLTexture>> mtlTexture)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedInternal),
|
||||
mMtlTexture(std::move(mtlTexture)) {
|
||||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
|
||||
mMtlUsage = [*mtlDesc usage];
|
||||
}
|
||||
|
||||
Texture::Texture(Device* device,
|
||||
|
@ -386,6 +392,7 @@ namespace dawn_native { namespace metal {
|
|||
mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
|
||||
iosurface:ioSurface
|
||||
plane:plane]);
|
||||
mMtlUsage = [*mtlDesc usage];
|
||||
|
||||
SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
|
||||
}
|
||||
|
@ -410,7 +417,7 @@ namespace dawn_native { namespace metal {
|
|||
const uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
|
||||
const double dClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.0 : 1.0;
|
||||
|
||||
if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0) {
|
||||
if ((mMtlUsage & MTLTextureUsageRenderTarget) != 0) {
|
||||
ASSERT(GetFormat().isRenderable);
|
||||
|
||||
// End the blit encoder if it is open.
|
||||
|
|
|
@ -1088,27 +1088,57 @@ std::ostringstream& DawnTestBase::AddTextureExpectationImpl(const char* file,
|
|||
return *(mDeferredExpectations.back().message.get());
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
const std::vector<float>& expected) {
|
||||
std::ostringstream& DawnTestBase::ExpectSampledFloatDataImpl(wgpu::TextureView textureView,
|
||||
const char* wgslTextureType,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t sampleCount,
|
||||
detail::Expectation* expectation) {
|
||||
std::ostringstream shaderSource;
|
||||
shaderSource << "let width : u32 = " << width << "u;\n";
|
||||
shaderSource << "[[group(0), binding(0)]] var tex : " << wgslTextureType << ";\n";
|
||||
shaderSource << R"(
|
||||
[[block]] struct Result {
|
||||
values : array<f32>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var tex : texture_depth_2d;
|
||||
[[group(0), binding(1)]] var<storage, read_write> result : Result;
|
||||
)";
|
||||
shaderSource << "let componentCount : u32 = " << componentCount << "u;\n";
|
||||
shaderSource << "let sampleCount : u32 = " << sampleCount << "u;\n";
|
||||
|
||||
shaderSource << "fn doTextureLoad(t: " << wgslTextureType
|
||||
<< ", coord: vec2<i32>, sample: u32, component: u32) -> f32";
|
||||
if (sampleCount > 1) {
|
||||
shaderSource << R"({
|
||||
return textureLoad(tex, coord, i32(sample))[component];
|
||||
})";
|
||||
} else {
|
||||
if (strcmp(wgslTextureType, "texture_depth_2d") == 0) {
|
||||
ASSERT(componentCount == 1);
|
||||
shaderSource << R"({
|
||||
return textureLoad(tex, coord, 0);
|
||||
})";
|
||||
} else {
|
||||
shaderSource << R"({
|
||||
return textureLoad(tex, coord, 0)[component];
|
||||
})";
|
||||
}
|
||||
}
|
||||
shaderSource << R"(
|
||||
[[stage(compute), workgroup_size(1)]] fn main(
|
||||
[[builtin(global_invocation_id)]] GlobalInvocationId : vec3<u32>
|
||||
) {
|
||||
result.values[GlobalInvocationId.y * width + GlobalInvocationId.x] = textureLoad(
|
||||
tex, vec2<i32>(i32(GlobalInvocationId.x), i32(GlobalInvocationId.y)), 0);
|
||||
let baseOutIndex = GlobalInvocationId.y * width + GlobalInvocationId.x;
|
||||
for (var s = 0u; s < sampleCount; s = s + 1u) {
|
||||
for (var c = 0u; c < componentCount; c = c + 1u) {
|
||||
result.values[
|
||||
baseOutIndex * sampleCount * componentCount +
|
||||
s * componentCount +
|
||||
c
|
||||
] = doTextureLoad(tex, vec2<i32>(GlobalInvocationId.xy), s, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1122,22 +1152,13 @@ std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
|||
|
||||
// Create and initialize the slot buffer so that it won't unexpectedly affect the count of
|
||||
// resources lazily cleared.
|
||||
const std::vector<float> initialBufferData(width * height, 0.f);
|
||||
const std::vector<float> initialBufferData(width * height * componentCount * sampleCount, 0.f);
|
||||
wgpu::Buffer readbackBuffer = utils::CreateBufferFromData(
|
||||
device, initialBufferData.data(), sizeof(float) * width * height,
|
||||
device, initialBufferData.data(), sizeof(float) * initialBufferData.size(),
|
||||
wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::Storage);
|
||||
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.baseArrayLayer = arrayLayer;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
|
||||
wgpu::BindGroup bindGroup =
|
||||
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||
{{0, texture.CreateView(&viewDesc)}, {1, readbackBuffer}});
|
||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||
{{0, textureView}, {1, readbackBuffer}});
|
||||
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass();
|
||||
|
@ -1148,8 +1169,62 @@ std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
|||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
return EXPECT_BUFFER_FLOAT_RANGE_ABOUT_EQ(expected.data(), readbackBuffer, 0, expected.size(),
|
||||
0.00001);
|
||||
return EXPECT_BUFFER(readbackBuffer, 0, initialBufferData.size() * sizeof(float), expectation);
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectSampledFloatData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
detail::Expectation* expectation) {
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.baseArrayLayer = arrayLayer;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
|
||||
return ExpectSampledFloatDataImpl(texture.CreateView(&viewDesc), "texture_2d<f32>", width,
|
||||
height, componentCount, 1, expectation);
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectMultisampledFloatData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t sampleCount,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
detail::Expectation* expectation) {
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.baseArrayLayer = arrayLayer;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
|
||||
return ExpectSampledFloatDataImpl(texture.CreateView(&viewDesc), "texture_multisampled_2d<f32>",
|
||||
width, height, componentCount, sampleCount, expectation);
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
detail::Expectation* expectation) {
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.baseArrayLayer = arrayLayer;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
|
||||
return ExpectSampledFloatDataImpl(texture.CreateView(&viewDesc), "texture_depth_2d", width,
|
||||
height, 1, 1, expectation);
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectAttachmentDepthStencilTestData(
|
||||
|
|
|
@ -74,10 +74,6 @@
|
|||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_RANGE_ABOUT_EQ(expected, buffer, offset, count, tolerance) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count, tolerance))
|
||||
|
||||
// Test a pixel of the mip level 0 of a 2D texture.
|
||||
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
|
||||
AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
|
||||
|
@ -407,12 +403,29 @@ class DawnTestBase {
|
|||
level, aspect, sizeof(T), bytesPerRow);
|
||||
}
|
||||
|
||||
std::ostringstream& ExpectSampledFloatData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
detail::Expectation* expectation);
|
||||
|
||||
std::ostringstream& ExpectMultisampledFloatData(wgpu::Texture texture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t sampleCount,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
detail::Expectation* expectation);
|
||||
|
||||
std::ostringstream& ExpectSampledDepthData(wgpu::Texture depthTexture,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
const std::vector<float>& expected);
|
||||
detail::Expectation* expectation);
|
||||
|
||||
// Check depth by uploading expected data to a sampled texture, writing it out as a depth
|
||||
// attachment, and then using the "equals" depth test to check the contents are the same.
|
||||
|
@ -485,6 +498,14 @@ class DawnTestBase {
|
|||
uint32_t dataSize,
|
||||
uint32_t bytesPerRow);
|
||||
|
||||
std::ostringstream& ExpectSampledFloatDataImpl(wgpu::TextureView textureView,
|
||||
const char* wgslTextureType,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t componentCount,
|
||||
uint32_t sampleCount,
|
||||
detail::Expectation* expectation);
|
||||
|
||||
// MapRead buffers used to get data for the expectations
|
||||
struct ReadbackSlot {
|
||||
wgpu::Buffer buffer;
|
||||
|
|
|
@ -100,7 +100,9 @@ namespace {
|
|||
switch (GetParam().mCheck) {
|
||||
case Check::SampleDepth: {
|
||||
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
|
||||
ExpectSampledDepthData(texture, mipSize, mipSize, 0, mipLevel, expectedDepth)
|
||||
ExpectSampledDepthData(texture, mipSize, mipSize, 0, mipLevel,
|
||||
new detail::ExpectEq<float>(
|
||||
expectedDepth.data(), expectedDepth.size(), 0.0001))
|
||||
<< "sample depth mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -27,9 +27,19 @@ namespace {
|
|||
using Usage = wgpu::TextureUsage;
|
||||
using Dimension = wgpu::TextureDimension;
|
||||
using DepthOrArrayLayers = uint32_t;
|
||||
using MipCount = uint32_t;
|
||||
using Mip = uint32_t;
|
||||
using SampleCount = uint32_t;
|
||||
|
||||
DAWN_TEST_PARAM_STRUCT(Params, Format, Aspect, Usage, Dimension, DepthOrArrayLayers, Mip)
|
||||
DAWN_TEST_PARAM_STRUCT(Params,
|
||||
Format,
|
||||
Aspect,
|
||||
Usage,
|
||||
Dimension,
|
||||
DepthOrArrayLayers,
|
||||
MipCount,
|
||||
Mip,
|
||||
SampleCount)
|
||||
|
||||
template <typename T>
|
||||
class ExpectNonZero : public detail::CustomTextureExpectation {
|
||||
|
@ -49,8 +59,8 @@ namespace {
|
|||
for (size_t i = 0; i < size / DataSize(); ++i) {
|
||||
if (actual[i] != value) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Expected data[" << i << "] to be " << value << ", actual "
|
||||
<< actual[i] << std::endl;
|
||||
<< "Expected data[" << i << "] to match non-zero value " << value
|
||||
<< ", actual " << actual[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +74,6 @@ namespace {
|
|||
class NonzeroTextureCreationTests : public DawnTestWithParams<Params> {
|
||||
protected:
|
||||
constexpr static uint32_t kSize = 128;
|
||||
constexpr static uint32_t kMipLevelCount = 4;
|
||||
|
||||
std::vector<const char*> GetRequiredExtensions() override {
|
||||
if (GetParam().mFormat == wgpu::TextureFormat::BC1RGBAUnorm &&
|
||||
|
@ -130,10 +139,10 @@ namespace {
|
|||
descriptor.size.width = kSize;
|
||||
descriptor.size.height = kSize;
|
||||
descriptor.size.depthOrArrayLayers = GetParam().mDepthOrArrayLayers;
|
||||
descriptor.sampleCount = 1;
|
||||
descriptor.sampleCount = GetParam().mSampleCount;
|
||||
descriptor.format = GetParam().mFormat;
|
||||
descriptor.usage = GetParam().mUsage;
|
||||
descriptor.mipLevelCount = kMipLevelCount;
|
||||
descriptor.mipLevelCount = GetParam().mMipCount;
|
||||
|
||||
wgpu::Texture texture = device.CreateTexture(&descriptor);
|
||||
|
||||
|
@ -142,22 +151,39 @@ namespace {
|
|||
uint32_t depthOrArrayLayers = GetParam().mDimension == wgpu::TextureDimension::e3D
|
||||
? std::max(GetParam().mDepthOrArrayLayers >> mip, 1u)
|
||||
: GetParam().mDepthOrArrayLayers;
|
||||
|
||||
switch (GetParam().mFormat) {
|
||||
case wgpu::TextureFormat::R8Unorm: {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint8_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
if (GetParam().mSampleCount > 1) {
|
||||
ExpectMultisampledFloatData(texture, mipSize, mipSize, 1,
|
||||
GetParam().mSampleCount, 0, mip,
|
||||
new ExpectNonZero<float>());
|
||||
} else {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint8_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureFormat::RG8Unorm: {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint16_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
if (GetParam().mSampleCount > 1) {
|
||||
ExpectMultisampledFloatData(texture, mipSize, mipSize, 2,
|
||||
GetParam().mSampleCount, 0, mip,
|
||||
new ExpectNonZero<float>());
|
||||
} else {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint16_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureFormat::RGBA8Unorm:
|
||||
case wgpu::TextureFormat::RGBA8Snorm: {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint32_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
if (GetParam().mSampleCount > 1) {
|
||||
ExpectMultisampledFloatData(texture, mipSize, mipSize, 4,
|
||||
GetParam().mSampleCount, 0, mip,
|
||||
new ExpectNonZero<float>());
|
||||
} else {
|
||||
EXPECT_TEXTURE_EQ(new ExpectNonZero<uint32_t>(), texture, {0, 0, 0},
|
||||
{mipSize, mipSize, depthOrArrayLayers}, mip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureFormat::Depth32Float: {
|
||||
|
@ -168,18 +194,10 @@ namespace {
|
|||
case wgpu::TextureFormat::Depth24PlusStencil8: {
|
||||
switch (GetParam().mAspect) {
|
||||
case wgpu::TextureAspect::DepthOnly: {
|
||||
uint32_t value = 0x01010101;
|
||||
float fValue = *reinterpret_cast<float*>(&value);
|
||||
std::vector<float> expectedDepth(
|
||||
mipSize * mipSize,
|
||||
(IsVulkan() || IsOpenGL() ||
|
||||
(GetParam().mUsage & wgpu::TextureUsage::RenderAttachment) != 0)
|
||||
? 1.f
|
||||
: fValue);
|
||||
for (uint32_t arrayLayer = 0;
|
||||
arrayLayer < GetParam().mDepthOrArrayLayers; ++arrayLayer) {
|
||||
ExpectSampledDepthData(texture, mipSize, mipSize, arrayLayer, mip,
|
||||
expectedDepth)
|
||||
new ExpectNonZero<float>())
|
||||
<< "arrayLayer " << arrayLayer;
|
||||
}
|
||||
break;
|
||||
|
@ -250,6 +268,7 @@ namespace {
|
|||
class NonzeroCompressedTextureCreationTests : public NonzeroTextureCreationTests {};
|
||||
class NonzeroDepthTextureCreationTests : public NonzeroTextureCreationTests {};
|
||||
class NonzeroDepthStencilTextureCreationTests : public NonzeroTextureCreationTests {};
|
||||
class NonzeroMultisampledTextureCreationTests : public NonzeroTextureCreationTests {};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -278,7 +297,10 @@ TEST_P(NonzeroDepthStencilTextureCreationTests, TextureCreationClears) {
|
|||
Run();
|
||||
}
|
||||
|
||||
// TODO(crbug.com/794): Test/implement texture initialization for multisampled textures.
|
||||
// Test that texture clears to a non-zero value because toggle is enabled.
|
||||
TEST_P(NonzeroMultisampledTextureCreationTests, TextureCreationClears) {
|
||||
Run();
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(
|
||||
NonzeroTextureCreationTests,
|
||||
|
@ -297,8 +319,11 @@ DAWN_INSTANTIATE_TEST_P(
|
|||
{wgpu::TextureUsage(wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc),
|
||||
wgpu::TextureUsage::CopySrc},
|
||||
{wgpu::TextureDimension::e2D, wgpu::TextureDimension::e3D},
|
||||
{1u, 7u},
|
||||
{0u, 1u, 2u, 3u});
|
||||
{1u, 7u}, // depth or array layers
|
||||
{4u}, // mip count
|
||||
{0u, 1u, 2u, 3u}, // mip
|
||||
{1u} // sample count
|
||||
);
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(NonzeroNonrenderableTextureCreationTests,
|
||||
{D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
|
@ -315,8 +340,11 @@ DAWN_INSTANTIATE_TEST_P(NonzeroNonrenderableTextureCreationTests,
|
|||
{wgpu::TextureAspect::All},
|
||||
{wgpu::TextureUsage::CopySrc},
|
||||
{wgpu::TextureDimension::e2D, wgpu::TextureDimension::e3D},
|
||||
{1u, 7u},
|
||||
{0u, 1u, 2u, 3u});
|
||||
{1u, 7u}, // depth or array layers
|
||||
{4u}, // mip count
|
||||
{0u, 1u, 2u, 3u}, // mip
|
||||
{1u} // sample count
|
||||
);
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(NonzeroCompressedTextureCreationTests,
|
||||
{D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
|
@ -333,8 +361,11 @@ DAWN_INSTANTIATE_TEST_P(NonzeroCompressedTextureCreationTests,
|
|||
{wgpu::TextureAspect::All},
|
||||
{wgpu::TextureUsage::CopySrc},
|
||||
{wgpu::TextureDimension::e2D},
|
||||
{1u, 7u},
|
||||
{0u, 1u, 2u, 3u});
|
||||
{1u, 7u}, // depth or array layers
|
||||
{4u}, // mip count
|
||||
{0u, 1u, 2u, 3u}, // mip
|
||||
{1u} // sample count
|
||||
);
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(NonzeroDepthTextureCreationTests,
|
||||
{D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
|
@ -353,8 +384,11 @@ DAWN_INSTANTIATE_TEST_P(NonzeroDepthTextureCreationTests,
|
|||
wgpu::TextureUsage::CopySrc),
|
||||
wgpu::TextureUsage::CopySrc},
|
||||
{wgpu::TextureDimension::e2D},
|
||||
{1u, 7u},
|
||||
{0u, 1u, 2u, 3u});
|
||||
{1u, 7u}, // depth or array layers
|
||||
{4u}, // mip count
|
||||
{0u, 1u, 2u, 3u}, // mip
|
||||
{1u} // sample count
|
||||
);
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(
|
||||
NonzeroDepthStencilTextureCreationTests,
|
||||
|
@ -374,5 +408,31 @@ DAWN_INSTANTIATE_TEST_P(
|
|||
wgpu::TextureUsage::Sampled),
|
||||
wgpu::TextureUsage(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopySrc)},
|
||||
{wgpu::TextureDimension::e2D},
|
||||
{1u, 7u},
|
||||
{0u, 1u, 2u, 3u});
|
||||
{1u, 7u}, // depth or array layers
|
||||
{4u}, // mip count
|
||||
{0u, 1u, 2u, 3u}, // mip
|
||||
{1u} // sample count
|
||||
);
|
||||
|
||||
DAWN_INSTANTIATE_TEST_P(
|
||||
NonzeroMultisampledTextureCreationTests,
|
||||
{D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
{"lazy_clear_resource_on_first_use"}),
|
||||
MetalBackend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
{"lazy_clear_resource_on_first_use"}),
|
||||
OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
{"lazy_clear_resource_on_first_use"}),
|
||||
OpenGLESBackend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
{"lazy_clear_resource_on_first_use"}),
|
||||
VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"},
|
||||
{"lazy_clear_resource_on_first_use"})},
|
||||
{wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, wgpu::TextureFormat::RGBA8Unorm},
|
||||
{wgpu::TextureAspect::All},
|
||||
{wgpu::TextureUsage(wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::Sampled),
|
||||
wgpu::TextureUsage::Sampled},
|
||||
{wgpu::TextureDimension::e2D},
|
||||
{1u}, // depth or array layers
|
||||
{1u}, // mip count
|
||||
{0u}, // mip
|
||||
{4u} // sample count
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue