123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Math/MatrixUtils.h>
- #include <Atom/RHI/CommandList.h>
- #include <Atom/RPI.Public/Shader/Shader.h>
- #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
- #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
- #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
- #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/std/createdestroy.h>
- #include <RHI/AlphaToCoverageExampleComponent.h>
- #include <SampleComponentManager.h>
- #include <Utils/Utils.h>
- namespace AtomSampleViewer
- {
- namespace AlphaToCoverage
- {
- const char* SampleName = "AlphaToCoverageExample";
- const char* ShaderFilePath = "Shaders/RHI/TexturedSurface.azshader";
- const char* TextureFilePath = "TestData/Textures/Foliage_Leaves_0_BaseColor.dds.streamingimage";
- }
- void AlphaToCoverageExampleComponent::Reflect(AZ::ReflectContext* context)
- {
- if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
- {
- serializeContext->Class<AlphaToCoverageExampleComponent, AZ::Component>()
- ->Version(0)
- ;
- }
- }
- AlphaToCoverageExampleComponent::AlphaToCoverageExampleComponent()
- {
- m_supportRHISamplePipeline = true;
- }
- void AlphaToCoverageExampleComponent::Activate()
- {
- using namespace AZ;
- RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
- m_inputAssemblyBufferPool = aznew RHI::BufferPool();
- RHI::BufferPoolDescriptor bufferPoolDesc;
- bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
- bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
- m_inputAssemblyBufferPool->Init(bufferPoolDesc);
- m_depthImageAttachmentId = RHI::AttachmentId("A2C_Depth");
- m_multisamleDepthImageAttachmentId = RHI::AttachmentId("A2C_MSAA_Depth");
- m_resolveImageAttachmentId = RHI::AttachmentId("A2C_Resolve");
- CreateResources();
- CreateScopeResources(BlendType::SrcOver);
- CreateScopeResources(BlendType::AlphaTest);
- CreateScopeResources(BlendType::A2C_MSAA);
- // render A2C_MSAA first since it contains resolve
- CreateRectangleScopeProducer(BlendType::A2C_MSAA);
- CreateRectangleScopeProducer(BlendType::SrcOver);
- CreateRectangleScopeProducer(BlendType::AlphaTest);
-
- AZ::TickBus::Handler::BusConnect();
- AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
- }
- void AlphaToCoverageExampleComponent::Deactivate()
- {
- m_rectangleInputAssemblyBuffer = nullptr;
- m_inputAssemblyBufferPool = nullptr;
- m_pipelineStates.fill(nullptr);
- AZStd::for_each(m_shaderResourceGroups.begin(), m_shaderResourceGroups.end(), [](auto& srgs)
- {
- srgs.fill(nullptr);
- });
-
- AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
- m_windowContext = nullptr;
- m_scopeProducers.clear();
- }
- void AlphaToCoverageExampleComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
- {
- AZ_UNUSED(time);
- m_time += deltaTime;
- }
- void AlphaToCoverageExampleComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder)
- {
- using namespace AZ;
- const float baseAngle = fmod(m_time * AZ::Constants::TwoPi / 16, AZ::Constants::TwoPi); // 1 rotate for 16 seconds.
- const auto rotate0 = AZ::Matrix4x4::CreateRotationY(-baseAngle);
- const auto rotate1 = AZ::Matrix4x4::CreateRotationY(-baseAngle + AZ::Constants::HalfPi);
- const float rectHeight = 2 * m_targetDepth * tanf(m_fieldOfView / 2);
- const float rectWidth = rectHeight / 3;
- const auto scale = AZ::Matrix4x4::CreateScale(AZ::Vector3(rectWidth / 2, rectHeight / 2, rectWidth / 2));
- for (int32_t blendIndex = 0; blendIndex < s_numBlendTypes; ++blendIndex)
- {
- const auto translate = AZ::Matrix4x4::CreateTranslation(AZ::Vector3((blendIndex - 1) * rectWidth, 0.f, 0.f));
- const auto worldMatrix0 = translate * rotate0 * scale;
- const auto worldMatrix1 = translate * rotate1 * scale;
- auto& srg0 = m_shaderResourceGroups[blendIndex][0];
- auto& srg1 = m_shaderResourceGroups[blendIndex][1];
- if(srg0)
- {
- srg0->SetConstant(m_worldMatrixIndex, worldMatrix0);
- srg0->Compile();
- }
- if (srg1)
- {
- srg1->SetConstant(m_worldMatrixIndex, worldMatrix1);
- srg1->Compile();
- }
- }
- BasicRHIComponent::OnFramePrepare(frameGraphBuilder);
- }
- void AlphaToCoverageExampleComponent::CreateResources()
- {
- using namespace AZ;
- RHI::InputStreamLayoutBuilder layoutBuilder;
- layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
- layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
- m_rectangleInputStreamLayout = layoutBuilder.End();
- RectangleBufferData bufferData;
- SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
- m_rectangleInputAssemblyBuffer = aznew RHI::Buffer();
- RHI::ResultCode result = RHI::ResultCode::Success;
- RHI::BufferInitRequest request;
- request.m_buffer = m_rectangleInputAssemblyBuffer.get();
- request.m_descriptor = RHI::BufferDescriptor{RHI::BufferBindFlags::InputAssembly, sizeof(bufferData)};
- request.m_initialData = &bufferData;
- result = m_inputAssemblyBufferPool->InitBuffer(request);
- if (result != RHI::ResultCode::Success)
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to initialize position buffer with error code %d", result);
- return;
- }
- m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, 6, 0));
- m_geometryView.SetIndexBufferView({
- *m_rectangleInputAssemblyBuffer,
- offsetof(RectangleBufferData, m_indices),
- sizeof(RectangleBufferData::m_indices),
- RHI::IndexFormat::Uint16
- });
- m_geometryView.AddStreamBufferView({
- *m_rectangleInputAssemblyBuffer,
- offsetof(RectangleBufferData, m_positions),
- sizeof(RectangleBufferData::m_positions),
- sizeof(VertexPosition)
- });
-
- m_geometryView.AddStreamBufferView({
- *m_rectangleInputAssemblyBuffer,
- offsetof(RectangleBufferData, m_uvs),
- sizeof(RectangleBufferData::m_uvs),
- sizeof(VertexUV)
- });
-
- RHI::ValidateStreamBufferViews(m_rectangleInputStreamLayout, m_geometryView, m_geometryView.GetFullStreamBufferIndices());
- m_shader = LoadShader(AlphaToCoverage::ShaderFilePath, AlphaToCoverage::SampleName);
- if (!m_shader)
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to load shader.");
- return;
- }
- for (uint32_t blendIndex = 0; blendIndex < s_numBlendTypes; ++blendIndex)
- {
- for (uint32_t rectIndex = 0; rectIndex < s_numRectangles; ++rectIndex)
- {
- m_shaderResourceGroups[blendIndex][rectIndex] = CreateShaderResourceGroup(m_shader, "TexturedSurfaceSrg", AlphaToCoverage::SampleName);
- }
- }
- m_worldMatrixIndex.Reset();
- m_viewProjectionMatrixIndex.Reset();
- m_alphaTestRefValueIndex.Reset();
- const AZ::Vector3 upVector{0.f, 1.f, 0.f};
- const AZ::Vector3 lookAtPos{0.f, 0.f, 0.f};
- const float zNear = 0.1f, zFar = 10.f;
- const float screenAspect = 1.f;
- const AZ::Vector3 eyePosition{0.f, 0.f, m_targetDepth};
- Matrix4x4 projectionMatrix;
- MakePerspectiveFovMatrixRH(projectionMatrix, m_fieldOfView, screenAspect, zNear, zFar);
- const auto viewMatrix = CreateViewMatrix(eyePosition, upVector, lookAtPos);
- const auto viewProjectionMatrix = projectionMatrix * viewMatrix;
- const Name albedoMapId{"m_albedoMap"};
- AZ::RHI::ShaderInputImageIndex albedMapImageIndex;
- FindShaderInputIndex(&albedMapImageIndex, m_shaderResourceGroups[0][0], albedoMapId, AlphaToCoverage::SampleName);
- auto textureIamge = LoadStreamingImage(AlphaToCoverage::TextureFilePath, AlphaToCoverage::SampleName);
- if (!textureIamge)
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to load texture image.");
- }
- constexpr float alphaTestRefValue = 0.1f;
- for (uint32_t blendIndex = 0; blendIndex < s_numBlendTypes; ++blendIndex)
- {
- float alphaRefValue = blendIndex == static_cast<int32_t>(BlendType::AlphaTest) ? alphaTestRefValue : 0.f;
- for (uint32_t rectIndex = 0; rectIndex < s_numRectangles; ++rectIndex)
- {
- if (!m_shaderResourceGroups[blendIndex][rectIndex]->SetImage(albedMapImageIndex, textureIamge))
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to set image into shader resource group.");
- return;
- }
- if (!m_shaderResourceGroups[blendIndex][rectIndex]->SetConstant(m_viewProjectionMatrixIndex, viewProjectionMatrix))
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to set view projection matrix into shader resource group.");
- return;
- }
- if (!m_shaderResourceGroups[blendIndex][rectIndex]->SetConstant(m_alphaTestRefValueIndex, alphaRefValue))
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to set alpha test reference value into shader resource group.");
- return;
- }
- }
- }
- }
- void AlphaToCoverageExampleComponent::CreateScopeResources(BlendType type)
- {
- using namespace AZ;
- if(!m_shader)
- {
- return;
- }
- const bool useDepth = (type == BlendType::AlphaTest) || (type == BlendType::A2C_MSAA);
- const bool useResolve = (type == BlendType::A2C_MSAA);
- AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
- pipelineStateDescriptor.m_inputStreamLayout = m_rectangleInputStreamLayout;
- auto shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
- shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
- RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
- auto* subpass = attachmentsBuilder.AddSubpass();
- subpass->RenderTargetAttachment(m_outputFormat, useResolve);
- if (useDepth)
- {
- subpass->DepthStencilAttachment(s_depthFormat);
- }
- [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
- AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
- pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_depth.m_enable = useDepth;
- pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::LessEqual;
- pipelineStateDescriptor.m_renderStates.m_multisampleState.m_samples = useResolve ? s_sampleCount : 1;
- pipelineStateDescriptor.m_renderStates.m_rasterState.m_cullMode = RHI::CullMode::None;
- pipelineStateDescriptor.m_renderStates.m_blendState.m_alphaToCoverageEnable = pipelineStateDescriptor.m_renderStates.m_multisampleState.m_samples > 1;
- RHI::TargetBlendState& targetBlendState = pipelineStateDescriptor.m_renderStates.m_blendState.m_targets[0];
- if (type == BlendType::SrcOver)
- {
- targetBlendState.m_enable = true;
- targetBlendState.m_blendSource = RHI::BlendFactor::AlphaSource;
- targetBlendState.m_blendDest = RHI::BlendFactor::AlphaSourceInverse;
- targetBlendState.m_blendOp = RHI::BlendOp::Add;
- targetBlendState.m_blendAlphaSource = RHI::BlendFactor::One;
- targetBlendState.m_blendAlphaDest = RHI::BlendFactor::AlphaSourceInverse;
- targetBlendState.m_blendAlphaOp = RHI::BlendOp::Add;
- }
- auto& pipeline = m_pipelineStates[static_cast<uint32_t>(type)];
- pipeline = m_shader->AcquirePipelineState(pipelineStateDescriptor);
- if (!pipeline)
- {
- AZ_Error(AlphaToCoverage::SampleName, false, "Failed to acquire default pipeline state for shader '%s'", AlphaToCoverage::ShaderFilePath);
- return;
- }
- }
- void AlphaToCoverageExampleComponent::CreateRectangleScopeProducer(BlendType type)
- {
- using namespace AZ;
- const uint32_t typeIndex = static_cast<uint32_t>(type);
- // Creates a scope for blend type.
- const auto prepareFunction = [this, type](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] const ScopeData& scopeData)
- {
- // Bind the color attachment
- {
- RHI::ImageScopeAttachmentDescriptor descriptor;
- if (type == BlendType::A2C_MSAA)
- {
- auto colorImageDesc = RHI::ImageDescriptor::Create2D(
- RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderRead,
- m_outputWidth,
- m_outputHeight,
- m_outputFormat);
- colorImageDesc.m_multisampleState = RHI::MultisampleState(s_sampleCount, 0);
- frameGraph.GetAttachmentDatabase().CreateTransientImage(RHI::TransientImageDescriptor(m_resolveImageAttachmentId, colorImageDesc));
-
- descriptor.m_attachmentId = m_resolveImageAttachmentId;
- descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
- descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(1.f, 1.f, 1.f, 0.f);
- descriptor.m_loadStoreAction.m_storeAction = RHI::AttachmentStoreAction::DontCare;
- }
- else
- {
- descriptor.m_attachmentId = m_outputAttachmentId;
- descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
- descriptor.m_loadStoreAction.m_storeAction = RHI::AttachmentStoreAction::Store;
- }
- frameGraph.UseColorAttachment(descriptor);
- }
- // Bind the depth attachment
- if (type == BlendType::AlphaTest || type == BlendType::A2C_MSAA)
- {
- RHI::AttachmentId depthAttachmentId = (type == BlendType::AlphaTest) ? m_depthImageAttachmentId : m_multisamleDepthImageAttachmentId;
- auto depthImageDesc = RHI::ImageDescriptor::Create2D(
- RHI::ImageBindFlags::DepthStencil,
- m_outputWidth,
- m_outputHeight,
- s_depthFormat);
- depthImageDesc.m_multisampleState.m_samples = (type == BlendType::A2C_MSAA) ? s_sampleCount : 1;
- frameGraph.GetAttachmentDatabase().CreateTransientImage(RHI::TransientImageDescriptor(depthAttachmentId, depthImageDesc));
-
- RHI::ImageScopeAttachmentDescriptor descriptor;
- descriptor.m_attachmentId = depthAttachmentId;
- descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
- descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateDepth(1.f);
- descriptor.m_loadStoreAction.m_storeAction = RHI::AttachmentStoreAction::Store;
- frameGraph.UseDepthStencilAttachment(
- descriptor, RHI::ScopeAttachmentAccess::ReadWrite,
- AZ::RHI::ScopeAttachmentStage::EarlyFragmentTest | AZ::RHI::ScopeAttachmentStage::LateFragmentTest);
- }
- // Bind the resolve attachment
- if (type == BlendType::A2C_MSAA)
- {
- RHI::ResolveScopeAttachmentDescriptor descriptor;
- descriptor.m_attachmentId = m_outputAttachmentId;
- descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
- descriptor.m_loadStoreAction.m_storeAction = RHI::AttachmentStoreAction::Store;
- descriptor.m_resolveAttachmentId = m_resolveImageAttachmentId;
- frameGraph.UseResolveAttachment(descriptor);
- }
- // We will submit two draw item.
- frameGraph.SetEstimatedItemCount(2);
- };
- RHI::EmptyCompileFunction<ScopeData> compileFunction;
- const auto executeFunction = [this, typeIndex](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
- {
- RHI::CommandList* commandList = context.GetCommandList();
- // Set persistent viewport and scissor state.
- commandList->SetViewports(&m_viewport, 1);
- commandList->SetScissors(&m_scissor, 1);
- for (uint32_t rectIndex = context.GetSubmitRange().m_startIndex; rectIndex < context.GetSubmitRange().m_endIndex; ++rectIndex)
- {
- const RHI::DeviceShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[typeIndex][rectIndex]
- ->GetRHIShaderResourceGroup()
- ->GetDeviceShaderResourceGroup(
- context.GetDeviceIndex())
- .get() };
- RHI::DeviceDrawItem drawItem;
- drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
- drawItem.m_streamIndices = m_geometryView.GetFullStreamBufferIndices();
- drawItem.m_pipelineState = m_pipelineStates[typeIndex]->GetDevicePipelineState(context.GetDeviceIndex()).get();
- drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
- drawItem.m_shaderResourceGroups = shaderResourceGroups;
- // Submit the rectangle draw item.
- commandList->Submit(drawItem);
- }
- };
- const auto name = AZStd::string::format("BlendType_%d", typeIndex);
- const AZ::RHI::ScopeId rectangleScopeId(name);
- m_scopeProducers.emplace_back(
- aznew RHI::ScopeProducerFunction<
- ScopeData,
- decltype(prepareFunction),
- decltype(compileFunction),
- decltype(executeFunction)>(
- rectangleScopeId,
- ScopeData{},
- prepareFunction,
- compileFunction,
- executeFunction));
- }
- } // namespace AtomSampleViewer
|