Add test to reproduce Intel driver issues with CreatePlacedResource()
This patch adds a test to dawn_end2end_tests to reproduce a driver issue about creating textures with CreatePlacedResource() on Intel D3D12 drivers. Bug: chromium:1237175 Test: dawn_end2end_tests Change-Id: I26fe6c9b827d8a05cfe2336405e43c549e52ea50 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100567 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
7f06aa06ac
commit
f7e113d47e
|
@ -2732,3 +2732,204 @@ DAWN_INSTANTIATE_TEST_P(
|
||||||
{InitializationMethod::CopyBufferToTexture, InitializationMethod::WriteTexture,
|
{InitializationMethod::CopyBufferToTexture, InitializationMethod::WriteTexture,
|
||||||
InitializationMethod::CopyTextureToTexture},
|
InitializationMethod::CopyTextureToTexture},
|
||||||
{true, false});
|
{true, false});
|
||||||
|
|
||||||
|
// A series of regression tests for an Intel D3D12 driver issue about creating textures with
|
||||||
|
// CreatePlacedResource(). See crbug.com/1237175 for more details.
|
||||||
|
class T2TCopyFromDirtyHeapTests : public DawnTest {
|
||||||
|
public:
|
||||||
|
void DoTest(uint32_t layerCount, uint32_t levelCount) {
|
||||||
|
// TODO(crbug.com/1237175): Re-enable these tests when we add the workaround on the Intel
|
||||||
|
// D3D12 drivers.
|
||||||
|
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsD3D12());
|
||||||
|
std::vector<uint32_t> expectedData;
|
||||||
|
wgpu::Buffer uploadBuffer = GetUploadBufferAndExpectedData(&expectedData);
|
||||||
|
|
||||||
|
// First, create colorTexture1 and colorTexture2 and fill data into them.
|
||||||
|
wgpu::Texture colorTexture1 = Create2DTexture(kTextureSize, layerCount, levelCount);
|
||||||
|
Initialize2DTexture(colorTexture1, layerCount, levelCount, uploadBuffer);
|
||||||
|
wgpu::Texture colorTexture2 = Create2DTexture(kTextureSize, layerCount, levelCount);
|
||||||
|
Initialize2DTexture(colorTexture2, layerCount, levelCount, uploadBuffer);
|
||||||
|
|
||||||
|
// Next, destroy colorTexture1.
|
||||||
|
colorTexture1.Destroy();
|
||||||
|
|
||||||
|
// Ensure colorTexture1 has been destroyed on the backend.
|
||||||
|
EnsureSubmittedWorkDone();
|
||||||
|
// Call an empty queue.Submit to workaround crbug.com/dawn/833 where resources are not
|
||||||
|
// recycled until the next serial.
|
||||||
|
queue.Submit(0, nullptr);
|
||||||
|
EnsureSubmittedWorkDone();
|
||||||
|
|
||||||
|
// Then, try to create destinationTextures which should be allocated on the memory used by
|
||||||
|
// colorTexture1 previously, copy data from colorTexture2 into each destinationTexture and
|
||||||
|
// verify the data in destinationTexture.
|
||||||
|
std::vector<wgpu::Texture> destinationTextures;
|
||||||
|
|
||||||
|
for (uint32_t layer = 0; layer < layerCount; ++layer) {
|
||||||
|
for (uint32_t level = 0; level < levelCount; ++level) {
|
||||||
|
uint32_t textureSizeAtLevel = kTextureSize >> level;
|
||||||
|
wgpu::Texture destinationTexture = Create2DTexture(textureSizeAtLevel, 1, 1);
|
||||||
|
// Save all destinationTextures so that they won't be deleted during the test.
|
||||||
|
destinationTextures.push_back(destinationTexture);
|
||||||
|
|
||||||
|
CopyIntoStagingTextureAndVerifyTexelData(colorTexture2, level, layer,
|
||||||
|
destinationTexture, expectedData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::Buffer GetUploadBufferAndExpectedData(std::vector<uint32_t>* expectedData) {
|
||||||
|
const uint32_t kBytesPerRow =
|
||||||
|
Align(kBytesPerBlock * kTextureSize, kTextureBytesPerRowAlignment);
|
||||||
|
const size_t kBufferSize =
|
||||||
|
kBytesPerRow * (kTextureSize - 1) + kTextureSize * kBytesPerBlock;
|
||||||
|
|
||||||
|
expectedData->resize(kBufferSize / sizeof(uint32_t));
|
||||||
|
for (uint32_t y = 0; y < kTextureSize; ++y) {
|
||||||
|
for (uint32_t x = 0; x < kTextureSize * (kBytesPerBlock / sizeof(uint32_t)); ++x) {
|
||||||
|
uint32_t index = (kBytesPerRow / sizeof(uint32_t)) * y + x;
|
||||||
|
(*expectedData)[index] = x + y * 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::BufferDescriptor uploadBufferDesc = {};
|
||||||
|
uploadBufferDesc.size = kBufferSize;
|
||||||
|
uploadBufferDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
|
||||||
|
uploadBufferDesc.mappedAtCreation = true;
|
||||||
|
wgpu::Buffer uploadBuffer = device.CreateBuffer(&uploadBufferDesc);
|
||||||
|
|
||||||
|
memcpy(uploadBuffer.GetMappedRange(), expectedData->data(), kBufferSize);
|
||||||
|
uploadBuffer.Unmap();
|
||||||
|
|
||||||
|
return uploadBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::Texture Create2DTexture(uint32_t textureSize, uint32_t layerCount, uint32_t levelCount) {
|
||||||
|
wgpu::TextureDescriptor colorTextureDesc = {};
|
||||||
|
colorTextureDesc.format = kFormat;
|
||||||
|
colorTextureDesc.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||||
|
wgpu::TextureUsage::RenderAttachment;
|
||||||
|
colorTextureDesc.mipLevelCount = levelCount;
|
||||||
|
colorTextureDesc.size = {textureSize, textureSize, layerCount};
|
||||||
|
return device.CreateTexture(&colorTextureDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize2DTexture(wgpu::Texture texture,
|
||||||
|
uint32_t layerCount,
|
||||||
|
uint32_t levelCount,
|
||||||
|
wgpu::Buffer uploadBuffer) {
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
for (uint32_t layer = 0; layer < layerCount; ++layer) {
|
||||||
|
for (uint32_t level = 0; level < levelCount; ++level) {
|
||||||
|
wgpu::ImageCopyBuffer uploadCopyBuffer =
|
||||||
|
utils::CreateImageCopyBuffer(uploadBuffer, 0, kBytesPerRow, kTextureSize);
|
||||||
|
wgpu::ImageCopyTexture colorCopyTexture =
|
||||||
|
utils::CreateImageCopyTexture(texture, level, {0, 0, layer});
|
||||||
|
|
||||||
|
wgpu::Extent3D copySize = {kTextureSize >> level, kTextureSize >> level, 1};
|
||||||
|
encoder.CopyBufferToTexture(&uploadCopyBuffer, &colorCopyTexture, ©Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
|
queue.Submit(1, &commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyIntoStagingTextureAndVerifyTexelData(wgpu::Texture sourceTexture,
|
||||||
|
uint32_t copyLevel,
|
||||||
|
uint32_t copyLayer,
|
||||||
|
wgpu::Texture stagingTexture,
|
||||||
|
const std::vector<uint32_t>& expectedData) {
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
|
||||||
|
// Copy from miplevel = copyLevel and arrayLayer = copyLayer of sourceTexture into
|
||||||
|
// stagingTexture
|
||||||
|
wgpu::ImageCopyTexture colorCopyTexture =
|
||||||
|
utils::CreateImageCopyTexture(sourceTexture, copyLevel, {0, 0, copyLayer});
|
||||||
|
uint32_t stagingTextureSize = kTextureSize >> copyLevel;
|
||||||
|
wgpu::Extent3D copySize = {stagingTextureSize, stagingTextureSize, 1};
|
||||||
|
wgpu::ImageCopyTexture stagingCopyTexture = utils::CreateImageCopyTexture(stagingTexture);
|
||||||
|
encoder.CopyTextureToTexture(&colorCopyTexture, &stagingCopyTexture, ©Size);
|
||||||
|
|
||||||
|
// Copy from stagingTexture into readback buffer. Note that we don't use EXPECT_BUFFER_xxx()
|
||||||
|
// because the buffers with CopySrc | CopyDst may also be allocated on the same memory of
|
||||||
|
// colorTexture1, then stagingTexture will not be able to be allocated at that piece of
|
||||||
|
// memory, which is not what we intended to do.
|
||||||
|
const size_t kBufferSize =
|
||||||
|
kBytesPerRow * (stagingTextureSize - 1) + stagingTextureSize * kBytesPerBlock;
|
||||||
|
wgpu::BufferDescriptor readbackBufferDesc = {};
|
||||||
|
readbackBufferDesc.size = kBufferSize;
|
||||||
|
readbackBufferDesc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
|
||||||
|
wgpu::Buffer readbackBuffer = device.CreateBuffer(&readbackBufferDesc);
|
||||||
|
wgpu::ImageCopyBuffer readbackCopyBuffer =
|
||||||
|
utils::CreateImageCopyBuffer(readbackBuffer, 0, kBytesPerRow, kTextureSize);
|
||||||
|
encoder.CopyTextureToBuffer(&stagingCopyTexture, &readbackCopyBuffer, ©Size);
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
|
queue.Submit(1, &commandBuffer);
|
||||||
|
|
||||||
|
// Check the data in readback buffer
|
||||||
|
bool done = false;
|
||||||
|
readbackBuffer.MapAsync(
|
||||||
|
wgpu::MapMode::Read, 0, kBufferSize,
|
||||||
|
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||||
|
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
|
||||||
|
*static_cast<bool*>(userdata) = true;
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
while (!done) {
|
||||||
|
WaitABit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t* readbackData =
|
||||||
|
static_cast<const uint32_t*>(readbackBuffer.GetConstMappedRange());
|
||||||
|
for (uint32_t y = 0; y < stagingTextureSize; ++y) {
|
||||||
|
for (uint32_t x = 0; x < stagingTextureSize * (kBytesPerBlock / sizeof(uint32_t));
|
||||||
|
++x) {
|
||||||
|
uint32_t index = y * (kBytesPerRow / sizeof(uint32_t)) + x;
|
||||||
|
ASSERT_EQ(expectedData[index], readbackData[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readbackBuffer.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureSubmittedWorkDone() {
|
||||||
|
bool submittedWorkDone = false;
|
||||||
|
queue.OnSubmittedWorkDone(
|
||||||
|
0,
|
||||||
|
[](WGPUQueueWorkDoneStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUQueueWorkDoneStatus_Success);
|
||||||
|
*static_cast<bool*>(userdata) = true;
|
||||||
|
},
|
||||||
|
&submittedWorkDone);
|
||||||
|
while (!submittedWorkDone) {
|
||||||
|
WaitABit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint32_t kTextureSize = 63;
|
||||||
|
const wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA32Uint;
|
||||||
|
const uint32_t kBytesPerBlock = 16;
|
||||||
|
const uint32_t kBytesPerRow =
|
||||||
|
Align(kBytesPerBlock * kTextureSize, kTextureBytesPerRowAlignment);
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(T2TCopyFromDirtyHeapTests, From2DArrayTexture) {
|
||||||
|
constexpr uint32_t kLayerCount = 7;
|
||||||
|
constexpr uint32_t kLevelCount = 1;
|
||||||
|
DoTest(kLayerCount, kLevelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(T2TCopyFromDirtyHeapTests, From2DMultiMipmapLevelTexture) {
|
||||||
|
constexpr uint32_t kLayerCount = 1;
|
||||||
|
constexpr uint32_t kLevelCount = 5;
|
||||||
|
DoTest(kLayerCount, kLevelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INSTANTIATE_TEST(T2TCopyFromDirtyHeapTests,
|
||||||
|
D3D12Backend(),
|
||||||
|
MetalBackend(),
|
||||||
|
OpenGLBackend(),
|
||||||
|
OpenGLESBackend(),
|
||||||
|
VulkanBackend());
|
||||||
|
|
Loading…
Reference in New Issue