Ensure clearing attachments is done via renderpass loadop
Clear through loadop instead of standalone clear operation to optimize efficiency on modern desktop GPUs and mobile GPUs. Removed clear calls in TransitionForPass for render pass to help optimize clearing using loadop instead. Compute pass textures and sampled textures are still cleared in transition. Bug: dawn:145 Change-Id: I84082bdea3ed7be75683389132d8b296051731b7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8641 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Natasha Lee <natlee@microsoft.com>
This commit is contained in:
parent
ebb05399c0
commit
8cb23933b1
|
@ -503,11 +503,14 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
Texture* texture = ToBackend(usages.textures[i]);
|
Texture* texture = ToBackend(usages.textures[i]);
|
||||||
// TODO(natlee@microsoft.com): Update clearing here when subresource tracking is
|
// Clear textures that are not output attachments. Output attachments will be
|
||||||
// implemented
|
// cleared during record render pass if the texture subresource has not been
|
||||||
|
// initialized before the render pass.
|
||||||
|
if (!(usages.textureUsages[i] & dawn::TextureUsageBit::OutputAttachment)) {
|
||||||
texture->EnsureSubresourceContentInitialized(
|
texture->EnsureSubresourceContentInitialized(
|
||||||
commandList, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers());
|
commandList, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
|
@ -869,15 +872,26 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// Load op - color
|
// Load op - color
|
||||||
ASSERT(view->GetLevelCount() == 1);
|
ASSERT(view->GetLevelCount() == 1);
|
||||||
ASSERT(view->GetLayerCount() == 1);
|
ASSERT(view->GetLayerCount() == 1);
|
||||||
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
|
if (attachmentInfo.loadOp == dawn::LoadOp::Clear ||
|
||||||
|
(attachmentInfo.loadOp == dawn::LoadOp::Load &&
|
||||||
|
!view->GetTexture()->IsSubresourceContentInitialized(
|
||||||
|
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1))) {
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i];
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i];
|
||||||
commandList->ClearRenderTargetView(handle, &attachmentInfo.clearColor.r, 0,
|
commandList->ClearRenderTargetView(handle, &attachmentInfo.clearColor.r, 0,
|
||||||
nullptr);
|
nullptr);
|
||||||
} else if (attachmentInfo.loadOp == dawn::LoadOp::Load && view->GetTexture()) {
|
|
||||||
ToBackend(view->GetTexture())
|
|
||||||
->EnsureSubresourceContentInitialized(commandList, view->GetBaseMipLevel(),
|
|
||||||
1, view->GetBaseArrayLayer(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get());
|
||||||
|
if (resolveView != nullptr) {
|
||||||
|
// We need to set the resolve target to initialized so that it does not get
|
||||||
|
// cleared later in the pipeline. The texture will be resolved from the source
|
||||||
|
// color attachment, which will be correctly initialized.
|
||||||
|
ToBackend(resolveView->GetTexture())
|
||||||
|
->SetIsSubresourceContentInitialized(
|
||||||
|
resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||||
|
resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount());
|
||||||
|
}
|
||||||
|
|
||||||
switch (attachmentInfo.storeOp) {
|
switch (attachmentInfo.storeOp) {
|
||||||
case dawn::StoreOp::Store: {
|
case dawn::StoreOp::Store: {
|
||||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||||
|
|
|
@ -362,8 +362,14 @@ namespace dawn_native { namespace opengl {
|
||||||
auto TransitionForPass = [](const PassResourceUsage& usages) {
|
auto TransitionForPass = [](const PassResourceUsage& usages) {
|
||||||
for (size_t i = 0; i < usages.textures.size(); i++) {
|
for (size_t i = 0; i < usages.textures.size(); i++) {
|
||||||
Texture* texture = ToBackend(usages.textures[i]);
|
Texture* texture = ToBackend(usages.textures[i]);
|
||||||
texture->EnsureSubresourceContentInitialized(0, texture->GetNumMipLevels(), 0,
|
// We count the lazy clears for non output attachment textures and depth stencil
|
||||||
texture->GetArrayLayers());
|
// textures in order to match the backdoor lazy clear counts in Vulkan and D3D12.
|
||||||
|
bool isLazyClear =
|
||||||
|
((!(usages.textureUsages[i] & dawn::TextureUsageBit::OutputAttachment) &&
|
||||||
|
texture->GetFormat().IsColor()) ||
|
||||||
|
texture->GetFormat().HasDepthOrStencil());
|
||||||
|
texture->EnsureSubresourceContentInitialized(
|
||||||
|
0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers(), isLazyClear);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -221,20 +221,24 @@ namespace dawn_native { namespace opengl {
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount);
|
|
||||||
GetDevice()->IncrementLazyClearCountForTesting();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
|
void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
|
||||||
uint32_t levelCount,
|
uint32_t levelCount,
|
||||||
uint32_t baseArrayLayer,
|
uint32_t baseArrayLayer,
|
||||||
uint32_t layerCount) {
|
uint32_t layerCount,
|
||||||
|
bool isLazyClear) {
|
||||||
if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
|
if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||||
layerCount)) {
|
layerCount)) {
|
||||||
ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount);
|
ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount);
|
||||||
|
if (isLazyClear) {
|
||||||
|
GetDevice()->IncrementLazyClearCountForTesting();
|
||||||
|
}
|
||||||
|
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||||
|
layerCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,8 @@ namespace dawn_native { namespace opengl {
|
||||||
void EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
|
void EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
|
||||||
uint32_t levelCount,
|
uint32_t levelCount,
|
||||||
uint32_t baseArrayLayer,
|
uint32_t baseArrayLayer,
|
||||||
uint32_t layerCount);
|
uint32_t layerCount,
|
||||||
|
bool isLazyClear = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DestroyImpl() override;
|
void DestroyImpl() override;
|
||||||
|
|
|
@ -214,6 +214,18 @@ namespace dawn_native { namespace vulkan {
|
||||||
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1)) {
|
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1)) {
|
||||||
loadOp = dawn::LoadOp::Clear;
|
loadOp = dawn::LoadOp::Clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasResolveTarget) {
|
||||||
|
// We need to set the resolve target to initialized so that it does not get
|
||||||
|
// cleared later in the pipeline. The texture will be resolved from the
|
||||||
|
// source color attachment, which will be correctly initialized.
|
||||||
|
TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get());
|
||||||
|
ToBackend(resolveView->GetTexture())
|
||||||
|
->SetIsSubresourceContentInitialized(
|
||||||
|
resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||||
|
resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount());
|
||||||
|
}
|
||||||
|
|
||||||
switch (attachmentInfo.storeOp) {
|
switch (attachmentInfo.storeOp) {
|
||||||
case dawn::StoreOp::Store: {
|
case dawn::StoreOp::Store: {
|
||||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||||
|
@ -355,15 +367,17 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
Texture* texture = ToBackend(usages.textures[i]);
|
Texture* texture = ToBackend(usages.textures[i]);
|
||||||
|
// Clear textures that are not output attachments. Output attachments will be
|
||||||
// TODO(natlee@microsoft.com): Update clearing here when subresource tracking is
|
// cleared in RecordBeginRenderPass by setting the loadop to clear when the
|
||||||
// implemented
|
// texture subresource has not been initialized before the render pass.
|
||||||
texture->EnsureSubresourceContentInitialized(
|
if (!(usages.textureUsages[i] & dawn::TextureUsageBit::OutputAttachment)) {
|
||||||
recordingContext, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers());
|
texture->EnsureSubresourceContentInitialized(recordingContext, 0,
|
||||||
|
texture->GetNumMipLevels(), 0,
|
||||||
|
texture->GetArrayLayers());
|
||||||
|
}
|
||||||
texture->TransitionUsageNow(recordingContext, usages.textureUsages[i]);
|
texture->TransitionUsageNow(recordingContext, usages.textureUsages[i]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
|
const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
|
||||||
size_t nextPassNumber = 0;
|
size_t nextPassNumber = 0;
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ TEST_P(TextureZeroInitTest, RenderingMipMapClearsToZero) {
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
}
|
}
|
||||||
dawn::CommandBuffer commands = encoder.Finish();
|
dawn::CommandBuffer commands = encoder.Finish();
|
||||||
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
|
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
|
||||||
|
|
||||||
uint32_t mipSize = kSize >> 2;
|
uint32_t mipSize = kSize >> 2;
|
||||||
std::vector<RGBA8> expected(mipSize * mipSize, {0, 0, 0, 0});
|
std::vector<RGBA8> expected(mipSize * mipSize, {0, 0, 0, 0});
|
||||||
|
@ -149,7 +149,7 @@ TEST_P(TextureZeroInitTest, RenderingArrayLayerClearsToZero) {
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
}
|
}
|
||||||
dawn::CommandBuffer commands = encoder.Finish();
|
dawn::CommandBuffer commands = encoder.Finish();
|
||||||
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
|
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
|
||||||
|
|
||||||
std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
|
std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
|
||||||
|
|
||||||
|
@ -328,8 +328,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepth) {
|
||||||
pass.Draw(6, 1, 0, 0);
|
pass.Draw(6, 1, 0, 0);
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
// Expect 2 lazy clears, one for the srcTexture and one for the depthStencilTexture
|
// Expect 1 lazy clear for the depthStencilTexture
|
||||||
EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commandBuffer));
|
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
|
||||||
|
|
||||||
// Expect the texture to be red because depth test passed.
|
// Expect the texture to be red because depth test passed.
|
||||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||||
|
@ -363,8 +363,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingStencil) {
|
||||||
pass.Draw(6, 1, 0, 0);
|
pass.Draw(6, 1, 0, 0);
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
// Expect 2 lazy clears, one for srcTexture and one for depthStencilTexture.
|
// Expect 1 lazy clear for depthStencilTexture.
|
||||||
EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commandBuffer));
|
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
|
||||||
|
|
||||||
// Expect the texture to be red because stencil test passed.
|
// Expect the texture to be red because stencil test passed.
|
||||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||||
|
@ -397,8 +397,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) {
|
||||||
pass.Draw(6, 1, 0, 0);
|
pass.Draw(6, 1, 0, 0);
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
// Expect 2 lazy clears, one for srcTexture and one for depthStencilTexture.
|
// Expect 1 lazy clear for depthStencilTexture.
|
||||||
EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commandBuffer));
|
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
|
||||||
|
|
||||||
// Expect the texture to be red because both depth and stencil tests passed.
|
// Expect the texture to be red because both depth and stencil tests passed.
|
||||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||||
|
@ -419,7 +419,7 @@ TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
|
|
||||||
dawn::CommandBuffer commands = encoder.Finish();
|
dawn::CommandBuffer commands = encoder.Finish();
|
||||||
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
|
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
|
||||||
|
|
||||||
std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
|
std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
|
||||||
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 0);
|
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 0);
|
||||||
|
@ -487,8 +487,8 @@ TEST_P(TextureZeroInitTest, RenderPassSampledTextureClear) {
|
||||||
pass.Draw(6, 1, 0, 0);
|
pass.Draw(6, 1, 0, 0);
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
dawn::CommandBuffer commands = encoder.Finish();
|
dawn::CommandBuffer commands = encoder.Finish();
|
||||||
// Expect 2 lazy clears, one for the sampled texture src and one for the rendered target texture
|
// Expect 1 lazy clear for sampled texture
|
||||||
EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commands));
|
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
|
||||||
|
|
||||||
// Expect the rendered texture to be cleared
|
// Expect the rendered texture to be cleared
|
||||||
std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
|
std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
|
||||||
|
|
Loading…
Reference in New Issue