Add StoreOp::Clear
When storeOp is clear, texture subresource is set as not initialized Bug: dawn:145 Change-Id: I364d7239a7ebdb9d5a28a4af559f3212be7ef15a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11560 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
05be0ff348
commit
cf0e9d93f1
|
@ -708,7 +708,8 @@
|
|||
"store op": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
{"value": 0, "name": "store"}
|
||||
{"value": 0, "name": "store"},
|
||||
{"value": 1, "name": "clear"}
|
||||
]
|
||||
},
|
||||
"origin 3D": {
|
||||
|
|
|
@ -404,6 +404,12 @@ namespace dawn_native {
|
|||
"depth stencil format");
|
||||
}
|
||||
|
||||
// This validates that the depth storeOp and stencil storeOps are the same
|
||||
if (depthStencilAttachment->depthStoreOp != depthStencilAttachment->stencilStoreOp) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"The depth storeOp and stencil storeOp are not the same");
|
||||
}
|
||||
|
||||
// *sampleCount == 0 must only happen when there is no color attachment. In that case we
|
||||
// do not need to validate the sample count of the depth stencil attachment.
|
||||
const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
|
||||
|
|
|
@ -412,7 +412,8 @@ namespace dawn_native {
|
|||
return true;
|
||||
}
|
||||
|
||||
void TextureBase::SetIsSubresourceContentInitialized(uint32_t baseMipLevel,
|
||||
void TextureBase::SetIsSubresourceContentInitialized(bool isInitialized,
|
||||
uint32_t baseMipLevel,
|
||||
uint32_t levelCount,
|
||||
uint32_t baseArrayLayer,
|
||||
uint32_t layerCount) {
|
||||
|
@ -422,7 +423,7 @@ namespace dawn_native {
|
|||
++arrayLayer) {
|
||||
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer);
|
||||
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
|
||||
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = true;
|
||||
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ namespace dawn_native {
|
|||
uint32_t levelCount,
|
||||
uint32_t baseArrayLayer,
|
||||
uint32_t layerCount) const;
|
||||
void SetIsSubresourceContentInitialized(uint32_t baseMipLevel,
|
||||
void SetIsSubresourceContentInitialized(bool isInitialized,
|
||||
uint32_t baseMipLevel,
|
||||
uint32_t levelCount,
|
||||
uint32_t baseArrayLayer,
|
||||
uint32_t layerCount);
|
||||
|
|
|
@ -654,7 +654,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
if (IsCompleteSubresourceCopiedTo(texture, copy->copySize,
|
||||
copy->destination.mipLevel)) {
|
||||
texture->SetIsSubresourceContentInitialized(
|
||||
copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1);
|
||||
true, copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1);
|
||||
} else {
|
||||
texture->EnsureSubresourceContentInitialized(
|
||||
commandList, copy->destination.mipLevel, 1,
|
||||
|
@ -737,7 +737,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
if (IsCompleteSubresourceCopiedTo(destination, copy->copySize,
|
||||
copy->destination.mipLevel)) {
|
||||
destination->SetIsSubresourceContentInitialized(
|
||||
copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1);
|
||||
true, copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1);
|
||||
} else {
|
||||
destination->EnsureSubresourceContentInitialized(
|
||||
commandList, copy->destination.mipLevel, 1,
|
||||
|
@ -907,14 +907,19 @@ namespace dawn_native { namespace d3d12 {
|
|||
// color attachment, which will be correctly initialized.
|
||||
ToBackend(resolveView->GetTexture())
|
||||
->SetIsSubresourceContentInitialized(
|
||||
resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||
true, resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||
resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount());
|
||||
}
|
||||
|
||||
switch (attachmentInfo.storeOp) {
|
||||
case dawn::StoreOp::Store: {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
true, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
} break;
|
||||
|
||||
case dawn::StoreOp::Clear: {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
} break;
|
||||
|
||||
default: { UNREACHABLE(); } break;
|
||||
|
@ -966,12 +971,16 @@ namespace dawn_native { namespace d3d12 {
|
|||
0, nullptr);
|
||||
}
|
||||
|
||||
// TODO(natlee@microsoft.com): Need to fix when storeop discard is added
|
||||
if (attachmentInfo.depthStoreOp == dawn::StoreOp::Store &&
|
||||
attachmentInfo.stencilStoreOp == dawn::StoreOp::Store) {
|
||||
texture->SetIsSubresourceContentInitialized(
|
||||
view->GetBaseMipLevel(), view->GetLevelCount(), view->GetBaseArrayLayer(),
|
||||
view->GetLayerCount());
|
||||
true, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
} else if (attachmentInfo.depthStoreOp == dawn::StoreOp::Clear &&
|
||||
attachmentInfo.stencilStoreOp == dawn::StoreOp::Clear) {
|
||||
texture->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
const TextureDescriptor* descriptor,
|
||||
ID3D12Resource* nativeTexture)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedExternal), mResource(nativeTexture) {
|
||||
SetIsSubresourceContentInitialized(0, descriptor->mipLevelCount, 0,
|
||||
SetIsSubresourceContentInitialized(true, 0, descriptor->mipLevelCount, 0,
|
||||
descriptor->arrayLayerCount);
|
||||
}
|
||||
|
||||
|
@ -483,7 +483,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
TextureBase::ClearValue clearValue) {
|
||||
// TODO(jiawei.shao@intel.com): initialize the textures in compressed formats with copies.
|
||||
if (GetFormat().isCompressed) {
|
||||
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||
SetIsSubresourceContentInitialized(true, baseMipLevel, levelCount, baseArrayLayer,
|
||||
layerCount);
|
||||
return {};
|
||||
}
|
||||
|
@ -579,7 +579,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
}
|
||||
if (clearValue == TextureBase::ClearValue::Zero) {
|
||||
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||
SetIsSubresourceContentInitialized(true, baseMipLevel, levelCount, baseArrayLayer,
|
||||
layerCount);
|
||||
GetDevice()->IncrementLazyClearCountForTesting();
|
||||
}
|
||||
|
|
|
@ -467,8 +467,8 @@ namespace dawn_native { namespace opengl {
|
|||
GLenum target = texture->GetGLTarget();
|
||||
const GLFormat& format = texture->GetGLFormat();
|
||||
if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) {
|
||||
texture->SetIsSubresourceContentInitialized(dst.mipLevel, 1, dst.arrayLayer,
|
||||
1);
|
||||
texture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1,
|
||||
dst.arrayLayer, 1);
|
||||
} else {
|
||||
texture->EnsureSubresourceContentInitialized(dst.mipLevel, 1,
|
||||
dst.arrayLayer, 1);
|
||||
|
@ -609,7 +609,7 @@ namespace dawn_native { namespace opengl {
|
|||
srcTexture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer,
|
||||
1);
|
||||
if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) {
|
||||
dstTexture->SetIsSubresourceContentInitialized(dst.mipLevel, 1,
|
||||
dstTexture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1,
|
||||
dst.arrayLayer, 1);
|
||||
} else {
|
||||
dstTexture->EnsureSubresourceContentInitialized(dst.mipLevel, 1,
|
||||
|
@ -783,28 +783,49 @@ namespace dawn_native { namespace opengl {
|
|||
{
|
||||
for (uint32_t i :
|
||||
IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
||||
const auto& attachmentInfo = renderPass->colorAttachments[i];
|
||||
auto* attachmentInfo = &renderPass->colorAttachments[i];
|
||||
TextureView* view = ToBackend(attachmentInfo->view.Get());
|
||||
|
||||
// Load op - color
|
||||
// TODO(cwallez@chromium.org): Choose the clear function depending on the
|
||||
// componentType: things work for now because the clear color is always a float, but
|
||||
// when that's fixed will lose precision on integer formats when converting to
|
||||
// float.
|
||||
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
|
||||
if (attachmentInfo->loadOp == dawn::LoadOp::Clear) {
|
||||
gl.ColorMaski(i, true, true, true, true);
|
||||
gl.ClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r);
|
||||
gl.ClearBufferfv(GL_COLOR, i, &attachmentInfo->clearColor.r);
|
||||
}
|
||||
|
||||
switch (attachmentInfo->storeOp) {
|
||||
case dawn::StoreOp::Store: {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
true, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
} break;
|
||||
|
||||
case dawn::StoreOp::Clear: {
|
||||
// TODO(natlee@microsoft.com): call glDiscard to do optimization
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
} break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
||||
const auto& attachmentInfo = renderPass->depthStencilAttachment;
|
||||
const Format& attachmentFormat = attachmentInfo.view->GetTexture()->GetFormat();
|
||||
auto* attachmentInfo = &renderPass->depthStencilAttachment;
|
||||
const Format& attachmentFormat = attachmentInfo->view->GetTexture()->GetFormat();
|
||||
TextureView* view = ToBackend(attachmentInfo->view.Get());
|
||||
|
||||
// Load op - depth/stencil
|
||||
bool doDepthClear = attachmentFormat.HasDepth() &&
|
||||
(attachmentInfo.depthLoadOp == dawn::LoadOp::Clear);
|
||||
(attachmentInfo->depthLoadOp == dawn::LoadOp::Clear);
|
||||
bool doStencilClear = attachmentFormat.HasStencil() &&
|
||||
(attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear);
|
||||
(attachmentInfo->stencilLoadOp == dawn::LoadOp::Clear);
|
||||
|
||||
if (doDepthClear) {
|
||||
gl.DepthMask(GL_TRUE);
|
||||
|
@ -814,14 +835,26 @@ namespace dawn_native { namespace opengl {
|
|||
}
|
||||
|
||||
if (doDepthClear && doStencilClear) {
|
||||
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
|
||||
attachmentInfo.clearStencil);
|
||||
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo->clearDepth,
|
||||
attachmentInfo->clearStencil);
|
||||
} else if (doDepthClear) {
|
||||
gl.ClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
|
||||
gl.ClearBufferfv(GL_DEPTH, 0, &attachmentInfo->clearDepth);
|
||||
} else if (doStencilClear) {
|
||||
const GLint clearStencil = attachmentInfo.clearStencil;
|
||||
const GLint clearStencil = attachmentInfo->clearStencil;
|
||||
gl.ClearBufferiv(GL_STENCIL, 0, &clearStencil);
|
||||
}
|
||||
|
||||
if (attachmentInfo->depthStoreOp == dawn::StoreOp::Store &&
|
||||
attachmentInfo->stencilStoreOp == dawn::StoreOp::Store) {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
true, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
} else if (attachmentInfo->depthStoreOp == dawn::StoreOp::Clear &&
|
||||
attachmentInfo->stencilStoreOp == dawn::StoreOp::Clear) {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ namespace dawn_native { namespace opengl {
|
|||
if (isLazyClear) {
|
||||
GetDevice()->IncrementLazyClearCountForTesting();
|
||||
}
|
||||
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||
SetIsSubresourceContentInitialized(true, baseMipLevel, levelCount, baseArrayLayer,
|
||||
layerCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,14 +137,19 @@ namespace dawn_native { namespace vulkan {
|
|||
TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get());
|
||||
ToBackend(resolveView->GetTexture())
|
||||
->SetIsSubresourceContentInitialized(
|
||||
resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||
true, resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
||||
resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount());
|
||||
}
|
||||
|
||||
switch (attachmentInfo.storeOp) {
|
||||
case dawn::StoreOp::Store: {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
true, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
} break;
|
||||
|
||||
case dawn::StoreOp::Clear: {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
||||
} break;
|
||||
|
||||
default: { UNREACHABLE(); } break;
|
||||
|
@ -177,11 +182,15 @@ namespace dawn_native { namespace vulkan {
|
|||
query.SetDepthStencil(view->GetTexture()->GetFormat().format,
|
||||
attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp);
|
||||
|
||||
// TODO(natlee@microsoft.com): Need to fix when storeop discard is added
|
||||
if (attachmentInfo.depthStoreOp == dawn::StoreOp::Store &&
|
||||
attachmentInfo.stencilStoreOp == dawn::StoreOp::Store) {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
true, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
} else if (attachmentInfo.depthStoreOp == dawn::StoreOp::Clear &&
|
||||
attachmentInfo.stencilStoreOp == dawn::StoreOp::Clear) {
|
||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
||||
false, view->GetBaseMipLevel(), view->GetLevelCount(),
|
||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +409,7 @@ namespace dawn_native { namespace vulkan {
|
|||
subresource.mipLevel)) {
|
||||
// Since texture has been overwritten, it has been "initialized"
|
||||
dst.texture->SetIsSubresourceContentInitialized(
|
||||
subresource.mipLevel, 1, subresource.baseArrayLayer, 1);
|
||||
true, subresource.mipLevel, 1, subresource.baseArrayLayer, 1);
|
||||
} else {
|
||||
ToBackend(dst.texture)
|
||||
->EnsureSubresourceContentInitialized(recordingContext,
|
||||
|
@ -459,7 +468,7 @@ namespace dawn_native { namespace vulkan {
|
|||
if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize,
|
||||
dst.mipLevel)) {
|
||||
// Since destination texture has been overwritten, it has been "initialized"
|
||||
dst.texture->SetIsSubresourceContentInitialized(dst.mipLevel, 1,
|
||||
dst.texture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1,
|
||||
dst.arrayLayer, 1);
|
||||
} else {
|
||||
ToBackend(dst.texture)
|
||||
|
|
|
@ -512,7 +512,7 @@ namespace dawn_native { namespace vulkan {
|
|||
|
||||
// Don't clear imported texture if already cleared
|
||||
if (descriptor->isCleared) {
|
||||
SetIsSubresourceContentInitialized(0, 1, 0, 1);
|
||||
SetIsSubresourceContentInitialized(true, 0, 1, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,7 +724,7 @@ namespace dawn_native { namespace vulkan {
|
|||
}
|
||||
}
|
||||
if (clearValue == TextureBase::ClearValue::Zero) {
|
||||
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
|
||||
SetIsSubresourceContentInitialized(true, baseMipLevel, levelCount, baseArrayLayer,
|
||||
layerCount);
|
||||
device->IncrementLazyClearCountForTesting();
|
||||
}
|
||||
|
|
|
@ -52,22 +52,7 @@ class TextureZeroInitTest : public DawnTest {
|
|||
}
|
||||
dawn::RenderPipeline CreatePipelineForTest() {
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
||||
const char* vs =
|
||||
R"(#version 450
|
||||
const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f),
|
||||
vec2( 1.0f, 1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
|
||||
})";
|
||||
pipelineDescriptor.vertexStage.module =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vs);
|
||||
|
||||
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest();
|
||||
const char* fs =
|
||||
R"(#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
@ -83,6 +68,30 @@ class TextureZeroInitTest : public DawnTest {
|
|||
|
||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
}
|
||||
dawn::ShaderModule CreateBasicVertexShaderForTest() {
|
||||
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(#version 450
|
||||
const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f),
|
||||
vec2( 1.0f, 1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
}
|
||||
dawn::ShaderModule CreateSampledTextureFragmentShaderForTest() {
|
||||
return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment,
|
||||
R"(#version 450
|
||||
layout(set = 0, binding = 0) uniform sampler sampler0;
|
||||
layout(set = 0, binding = 1) uniform texture2D texture0;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = texelFetch(sampler2D(texture0, sampler0), ivec2(gl_FragCoord), 0);
|
||||
})");
|
||||
}
|
||||
constexpr static uint32_t kSize = 128;
|
||||
constexpr static uint32_t kUnalignedSize = 127;
|
||||
// All three texture formats used (RGBA8Unorm, Depth24PlusStencil8, and RGBA8Snorm) have the
|
||||
|
@ -161,8 +170,6 @@ TEST_P(TextureZeroInitTest, RenderingArrayLayerClearsToZero) {
|
|||
}
|
||||
|
||||
// This tests CopyBufferToTexture fully overwrites copy so lazy init is not needed.
|
||||
// TODO(natlee@microsoft.com): Add backdoor to dawn native to query the number of zero-inited
|
||||
// subresources
|
||||
TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
|
||||
dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
|
||||
4, 1,
|
||||
|
@ -452,29 +459,9 @@ TEST_P(TextureZeroInitTest, RenderPassSampledTextureClear) {
|
|||
// Create render pipeline
|
||||
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
|
||||
renderPipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
|
||||
renderPipelineDescriptor.vertexStage.module =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(#version 450
|
||||
const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f),
|
||||
vec2( 1.0f, 1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
renderPipelineDescriptor.cFragmentStage.module =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment,
|
||||
R"(#version 450
|
||||
layout(set = 0, binding = 0) uniform sampler sampler0;
|
||||
layout(set = 0, binding = 1) uniform texture2D texture0;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = texelFetch(sampler2D(texture0, sampler0), ivec2(gl_FragCoord), 0);
|
||||
})");
|
||||
renderPipelineDescriptor.cColorStates[0].format = kColorFormat;
|
||||
renderPipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest();
|
||||
renderPipelineDescriptor.cFragmentStage.module = CreateSampledTextureFragmentShaderForTest();
|
||||
dawn::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
|
||||
|
||||
// Create bindgroup
|
||||
|
@ -651,6 +638,144 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) {
|
|||
EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, 8);
|
||||
}
|
||||
|
||||
// This tests that storeOp clear resets resource state to uninitialized.
|
||||
// Start with a sample texture that is initialized with data.
|
||||
// Then expect the render texture to not store the data from sample texture
|
||||
// because it will be lazy cleared by the EXPECT_TEXTURE_RGBA8_EQ call.
|
||||
TEST_P(TextureZeroInitTest, RenderPassStoreOpClear) {
|
||||
// Create needed resources
|
||||
dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
|
||||
1, 1, dawn::TextureUsage::Sampled | dawn::TextureUsage::CopyDst, kColorFormat);
|
||||
dawn::Texture texture = device.CreateTexture(&descriptor);
|
||||
|
||||
dawn::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(
|
||||
1, 1, dawn::TextureUsage::CopySrc | dawn::TextureUsage::OutputAttachment, kColorFormat);
|
||||
dawn::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
|
||||
|
||||
dawn::SamplerDescriptor samplerDesc = utils::GetDefaultSamplerDescriptor();
|
||||
dawn::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||
|
||||
dawn::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
||||
device, {{0, dawn::ShaderStage::Fragment, dawn::BindingType::Sampler},
|
||||
{1, dawn::ShaderStage::Fragment, dawn::BindingType::SampledTexture}});
|
||||
|
||||
// Fill the sample texture with data
|
||||
std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 1);
|
||||
dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
|
||||
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
|
||||
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
|
||||
dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
|
||||
dawn::Extent3D copySize = {kSize, kSize, 1};
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size);
|
||||
dawn::CommandBuffer commands = encoder.Finish();
|
||||
// Expect 0 lazy clears because the texture will be completely copied to
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
|
||||
|
||||
// Create render pipeline
|
||||
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
|
||||
renderPipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
|
||||
renderPipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest();
|
||||
renderPipelineDescriptor.cFragmentStage.module = CreateSampledTextureFragmentShaderForTest();
|
||||
renderPipelineDescriptor.cColorStates[0].format = kColorFormat;
|
||||
dawn::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
|
||||
|
||||
// Create bindgroup
|
||||
dawn::BindGroup bindGroup =
|
||||
utils::MakeBindGroup(device, bindGroupLayout, {{0, sampler}, {1, texture.CreateView()}});
|
||||
|
||||
// Encode pass and submit
|
||||
encoder = device.CreateCommandEncoder();
|
||||
utils::ComboRenderPassDescriptor renderPassDesc({renderTexture.CreateView()});
|
||||
renderPassDesc.cColorAttachments[0].clearColor = {0.0, 0.0, 0.0, 0.0};
|
||||
renderPassDesc.cColorAttachments[0].loadOp = dawn::LoadOp::Clear;
|
||||
renderPassDesc.cColorAttachments[0].storeOp = dawn::StoreOp::Clear;
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
|
||||
pass.SetPipeline(renderPipeline);
|
||||
pass.SetBindGroup(0, bindGroup, 0, nullptr);
|
||||
pass.Draw(6, 1, 0, 0);
|
||||
pass.EndPass();
|
||||
commands = encoder.Finish();
|
||||
// Expect 0 lazy clears, sample texture is initialized by copyBufferToTexture and render texture
|
||||
// is cleared by loadop
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
|
||||
|
||||
// Expect the rendered texture to be cleared
|
||||
std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
|
||||
EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_RGBA8_EQ(expectedWithZeros.data(), renderTexture, 0, 0,
|
||||
kSize, kSize, 0, 0));
|
||||
}
|
||||
|
||||
// This tests storeOp Clear on depth and stencil textures.
|
||||
// We put the depth stencil texture through 2 passes:
|
||||
// 1) LoadOp::Clear and StoreOp::Clear, fail the depth and stencil test set in the render pipeline.
|
||||
// This means nothing is drawn and subresource is set as uninitialized.
|
||||
// 2) LoadOp::Load and StoreOp::Clear, pass the depth and stencil test set in the render pipeline.
|
||||
// Because LoadOp is Load and the subresource is uninitialized, the texture will be cleared to
|
||||
// 0's This means the depth and stencil test will pass and the red square is drawn.
|
||||
TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencilStoreOpClear) {
|
||||
dawn::TextureDescriptor srcDescriptor =
|
||||
CreateTextureDescriptor(1, 1,
|
||||
dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst |
|
||||
dawn::TextureUsage::OutputAttachment,
|
||||
kColorFormat);
|
||||
dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
|
||||
|
||||
dawn::TextureDescriptor depthStencilDescriptor =
|
||||
CreateTextureDescriptor(1, 1,
|
||||
dawn::TextureUsage::OutputAttachment | dawn::TextureUsage::CopySrc |
|
||||
dawn::TextureUsage::CopyDst,
|
||||
kDepthStencilFormat);
|
||||
dawn::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
|
||||
|
||||
// Setup the renderPass for the first pass.
|
||||
// We want to fail the depth and stencil test here so that nothing gets drawn and we can
|
||||
// see that the subresource correctly gets set as unintialized in the second pass
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateView()},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Clear;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 1.0f;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 1u;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Clear;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Clear;
|
||||
{
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.SetPipeline(CreatePipelineForTest());
|
||||
pass.Draw(6, 1, 0, 0);
|
||||
pass.EndPass();
|
||||
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
||||
// Expect 0 lazy clears, depth stencil texture will clear using loadop
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
|
||||
// The depth stencil test should fail and not draw because the depth stencil texture is
|
||||
// cleared to 1's by using loadOp clear and set values from descriptor.
|
||||
std::vector<RGBA8> expectedBlack(kSize * kSize, {0, 0, 0, 0});
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectedBlack.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
|
||||
}
|
||||
|
||||
// Now we put the depth stencil texture back into renderpass, it should be cleared by loadop
|
||||
// because storeOp clear sets the subresource as uninitialized
|
||||
{
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Load;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Load;
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.SetPipeline(CreatePipelineForTest());
|
||||
pass.Draw(6, 1, 0, 0);
|
||||
pass.EndPass();
|
||||
dawn::CommandBuffer commandBuffer = encoder.Finish();
|
||||
// Expect 0 lazy clears, depth stencil texture will clear using loadop
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
|
||||
// Now the depth stencil test should pass since depth stencil texture is cleared to 0's by
|
||||
// loadop load and uninitialized subresource, so we should have a red square
|
||||
std::vector<RGBA8> expectedRed(kSize * kSize, {255, 0, 0, 255});
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectedRed.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(
|
||||
TextureZeroInitTest,
|
||||
ForceWorkarounds(D3D12Backend, {"nonzero_clear_resources_on_creation_for_testing"}),
|
||||
|
|
|
@ -189,6 +189,54 @@ TEST_F(RenderPassDescriptorValidationTest, FormatMismatch) {
|
|||
}
|
||||
}
|
||||
|
||||
// Depth and stencil storeOps must match
|
||||
TEST_F(RenderPassDescriptorValidationTest, DepthStencilStoreOpMismatch) {
|
||||
constexpr uint32_t kArrayLayers = 1;
|
||||
constexpr uint32_t kLevelCount = 1;
|
||||
constexpr uint32_t kSize = 32;
|
||||
constexpr dawn::TextureFormat kColorFormat = dawn::TextureFormat::RGBA8Unorm;
|
||||
constexpr dawn::TextureFormat kDepthStencilFormat = dawn::TextureFormat::Depth24PlusStencil8;
|
||||
|
||||
dawn::Texture colorTexture = CreateTexture(device, dawn::TextureDimension::e2D, kColorFormat,
|
||||
kSize, kSize, kArrayLayers, kLevelCount);
|
||||
dawn::Texture depthStencilTexture =
|
||||
CreateTexture(device, dawn::TextureDimension::e2D, kDepthStencilFormat, kSize, kSize,
|
||||
kArrayLayers, kLevelCount);
|
||||
|
||||
dawn::TextureViewDescriptor descriptor;
|
||||
descriptor.dimension = dawn::TextureViewDimension::e2D;
|
||||
descriptor.baseArrayLayer = 0;
|
||||
descriptor.arrayLayerCount = kArrayLayers;
|
||||
descriptor.baseMipLevel = 0;
|
||||
descriptor.mipLevelCount = kLevelCount;
|
||||
dawn::TextureView colorTextureView = colorTexture.CreateView(&descriptor);
|
||||
dawn::TextureView depthStencilView = depthStencilTexture.CreateView(&descriptor);
|
||||
|
||||
// StoreOps mismatch causing the render pass to error
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Clear;
|
||||
AssertBeginRenderPassError(&renderPass);
|
||||
}
|
||||
|
||||
// StoreOps match so render pass is a success
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Store;
|
||||
AssertBeginRenderPassSuccess(&renderPass);
|
||||
}
|
||||
|
||||
// StoreOps match so render pass is a success
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Clear;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Clear;
|
||||
AssertBeginRenderPassSuccess(&renderPass);
|
||||
}
|
||||
}
|
||||
|
||||
// Currently only texture views with arrayLayerCount == 1 are allowed to be color and depth stencil
|
||||
// attachments
|
||||
TEST_F(RenderPassDescriptorValidationTest, TextureViewLayerCountForColorAndDepthStencil) {
|
||||
|
|
Loading…
Reference in New Issue