/* * 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 #include #include namespace AtomSampleViewer { AZ::RPI::Ptr RHISamplePass::Create(const AZ::RPI::PassDescriptor& descriptor) { AZ::RPI::Ptr pass = aznew RHISamplePass(descriptor); return AZStd::move(pass); } RHISamplePass::RHISamplePass(const AZ::RPI::PassDescriptor& descriptor) : AZ::RPI::RenderPass(descriptor) { m_flags.m_hasPipelineViewTag = true; m_pipelineViewTag = "MainCamera"; } RHISamplePass::~RHISamplePass() { m_rhiSample = nullptr; } const AZ::RPI::PipelineViewTag& RHISamplePass::GetPipelineViewTag() const { return m_pipelineViewTag; } void RHISamplePass::SetRHISample(BasicRHIComponent* sample) { m_rhiSample = sample; if (m_rhiSample) { m_rhiSample->SetOutputInfo(m_outputAttachment->m_descriptor.m_image.m_size.m_width , m_outputAttachment->m_descriptor.m_image.m_size.m_height , m_outputAttachment->m_descriptor.m_image.m_format , m_outputAttachment->GetAttachmentId()); } } void RHISamplePass::BuildInternal() { Base::BuildInternal(); // The RHISamplePass template should have one owned image attachment which is the render target m_outputAttachment = m_ownedAttachments[0]; // Force update pass attachment to get correct size and save it to local variables m_outputAttachment->Update(); // update output info for the rhi sample if (m_rhiSample) { SetRHISample(m_rhiSample); } } void RHISamplePass::FrameBeginInternal(FramePrepareParams params) { // Note: we can't preview the output attachment of this pass properly // Ideally, we should import RHISamplePass's scope producer first, then rhi sample's scope producers // then add readback scope and preview copy scope. // We can't do it since some of them private to RenderPass which we can't access here. // Import this pass's scope producer Base::FrameBeginInternal(params); // Import sample's scope producer if (m_rhiSample) { auto frameGraphBuilder = params.m_frameGraphBuilder; m_rhiSample->FrameBeginInternal(*frameGraphBuilder); for (AZStd::shared_ptr& producer : m_rhiSample->m_scopeProducers) { frameGraphBuilder->ImportScopeProducer(*producer); } } } uint32_t RHISamplePass::GetViewIndex() const { return m_viewIndex; } void RHISamplePass::SetViewIndex(const uint32_t viewIndex) { m_viewIndex = viewIndex; } bool BasicRHIComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) { using namespace AZ; const auto config = azrtti_cast(baseConfig); if (config != nullptr && config->m_windowContext) { m_windowContext = config->m_windowContext; return true; } return false; } void BasicRHIComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder) { // Check the swap chain since the system may still tick one more frame when window is closed and swapchain got destroied. if (!IsSupportedRHISamplePipeline() && m_windowContext->GetSwapChain()) { SetOutputInfoFromWindowContext(); FrameBeginInternal(frameGraphBuilder); for (AZStd::shared_ptr& producer : m_scopeProducers) { frameGraphBuilder.ImportScopeProducer(*producer); } } } void BasicRHIComponent::SetVertexPosition(VertexPosition* positionBuffer, int bufferIndex, float x, float y, float z) { positionBuffer[bufferIndex].m_position[0] = x; positionBuffer[bufferIndex].m_position[1] = y; positionBuffer[bufferIndex].m_position[2] = z; } void BasicRHIComponent::SetVertexPosition(VertexPosition* positionBuffer, int bufferIndex, const AZ::Vector3& position) { positionBuffer[bufferIndex].m_position[0] = position.GetX(); positionBuffer[bufferIndex].m_position[1] = position.GetY(); positionBuffer[bufferIndex].m_position[2] = position.GetZ(); } void BasicRHIComponent::SetVertexPosition(VertexPosition* positionBuffer, int bufferIndex, const VertexPosition& position) { positionBuffer[bufferIndex].m_position[0] = position.m_position[0]; positionBuffer[bufferIndex].m_position[1] = position.m_position[1]; positionBuffer[bufferIndex].m_position[2] = position.m_position[2]; } void BasicRHIComponent::SetVertexColor(VertexColor* colorBuffer, int bufferIndex, float r, float g, float b, float a) { colorBuffer[bufferIndex].m_color[0] = r; colorBuffer[bufferIndex].m_color[1] = g; colorBuffer[bufferIndex].m_color[2] = b; colorBuffer[bufferIndex].m_color[3] = a; } void BasicRHIComponent::SetVertexColor(VertexColor* colorBuffer, int bufferIndex, const AZ::Vector4& color) { colorBuffer[bufferIndex].m_color[0] = color.GetX(); colorBuffer[bufferIndex].m_color[1] = color.GetY(); colorBuffer[bufferIndex].m_color[2] = color.GetZ(); colorBuffer[bufferIndex].m_color[3] = color.GetW(); } void BasicRHIComponent::SetVertexColor(VertexColor* colorBuffer, int bufferIndex, const VertexColor& color) { colorBuffer[bufferIndex].m_color[0] = color.m_color[0]; colorBuffer[bufferIndex].m_color[1] = color.m_color[1]; colorBuffer[bufferIndex].m_color[2] = color.m_color[2]; colorBuffer[bufferIndex].m_color[3] = color.m_color[3]; } void BasicRHIComponent::SetVertexIndex(uint16_t* indexBuffer, int bufferIndex, const uint16_t index) { indexBuffer[bufferIndex] = index; } void BasicRHIComponent::SetVertexU(VertexU* uBuffer, int bufferIndex, float u) { uBuffer[bufferIndex].m_u = u; } void BasicRHIComponent::SetVertexUV(VertexUV* uvBuffer, int bufferIndex, float u, float v) { uvBuffer[bufferIndex].m_uv[0] = u; uvBuffer[bufferIndex].m_uv[1] = v; } void BasicRHIComponent::SetVertexUVW(VertexUVW* uvwBuffer, int bufferIndex, float u, float v, float w) { uvwBuffer[bufferIndex].m_uvw[0] = u; uvwBuffer[bufferIndex].m_uvw[1] = v; uvwBuffer[bufferIndex].m_uvw[2] = w; } void BasicRHIComponent::SetVertexUVW(VertexUVW* uvwBuffer, int bufferIndex, const AZ::Vector3& uvw) { uvwBuffer[bufferIndex].m_uvw[0] = uvw.GetX(); uvwBuffer[bufferIndex].m_uvw[1] = uvw.GetY(); uvwBuffer[bufferIndex].m_uvw[2] = uvw.GetZ(); } void BasicRHIComponent::SetVertexUVWX(VertexUVWX* uvwxBuffer, int bufferIndex, float u, float v, float w, float x) { uvwxBuffer[bufferIndex].m_uvwx[0] = u; uvwxBuffer[bufferIndex].m_uvwx[1] = v; uvwxBuffer[bufferIndex].m_uvwx[2] = w; uvwxBuffer[bufferIndex].m_uvwx[3] = x; } void BasicRHIComponent::SetVertexNormal(VertexNormal* normalBuffer, int bufferIndex, float nx, float ny, float nz) { normalBuffer[bufferIndex].m_normal[0] = nx; normalBuffer[bufferIndex].m_normal[1] = ny; normalBuffer[bufferIndex].m_normal[2] = nz; } void BasicRHIComponent::SetVertexNormal(VertexNormal* normalBuffer, int bufferIndex, const AZ::Vector3& normal) { normalBuffer[bufferIndex].m_normal[0] = normal.GetX(); normalBuffer[bufferIndex].m_normal[1] = normal.GetY(); normalBuffer[bufferIndex].m_normal[2] = normal.GetZ(); } void BasicRHIComponent::SetFullScreenRect(VertexPosition* positionBuffer, VertexUV* uvBuffer, uint16_t* indexBuffer) { SetVertexPosition(positionBuffer, 0, -1.0f, -1.0f, 0.0f); SetVertexPosition(positionBuffer, 1, -1.0f, 1.0f, 0.0f); SetVertexPosition(positionBuffer, 2, 1.0f, 1.0f, 0.0f); SetVertexPosition(positionBuffer, 3, 1.0f, -1.0f, 0.0f); if (uvBuffer) { SetVertexUV(uvBuffer, 0, 0.0f, 0.0f); SetVertexUV(uvBuffer, 1, 0.0f, 1.0f); SetVertexUV(uvBuffer, 2, 1.0f, 1.0f); SetVertexUV(uvBuffer, 3, 1.0f, 0.0f); } indexBuffer[0] = 0; indexBuffer[1] = 3; indexBuffer[2] = 1; indexBuffer[3] = 1; indexBuffer[4] = 3; indexBuffer[5] = 2; } void BasicRHIComponent::SetCube(VertexPosition* positionBuffer, VertexColor* colorBuffer, VertexNormal* normalBuffer, uint16_t* indexBuffer) { static AZ::Vector3 vertices[] = { //Front Face AZ::Vector3(1.0, 1.0, 1.0), AZ::Vector3(-1.0, 1.0, 1.0), AZ::Vector3(-1.0, -1.0, 1.0), AZ::Vector3(1.0, -1.0, 1.0), //Back Face AZ::Vector3(1.0, 1.0, -1.0), AZ::Vector3(-1.0, 1.0, -1.0), AZ::Vector3(-1.0, -1.0, -1.0), AZ::Vector3(1.0, -1.0, -1.0), //Left Face AZ::Vector3(-1.0, 1.0, 1.0), AZ::Vector3(-1.0, -1.0, 1.0), AZ::Vector3(-1.0, -1.0, -1.0), AZ::Vector3(-1.0, 1.0, -1.0), //Right Face AZ::Vector3(1.0, 1.0, 1.0), AZ::Vector3(1.0, -1.0, 1.0), AZ::Vector3(1.0, -1.0, -1.0), AZ::Vector3(1.0, 1.0, -1.0), //Top Face AZ::Vector3(1.0, 1.0, 1.0), AZ::Vector3(-1.0, 1.0, 1.0), AZ::Vector3(-1.0, 1.0, -1.0), AZ::Vector3(1.0, 1.0, -1.0), //Bottom Face AZ::Vector3(1.0, -1.0, 1.0), AZ::Vector3(-1.0, -1.0, 1.0), AZ::Vector3(-1.0, -1.0, -1.0), AZ::Vector3(1.0, -1.0, -1.0) }; static AZ::Vector4 colors[] = { //Front Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), //Back Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), //Left Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), //Right Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), //Top Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), //Bottom Face AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0), AZ::Vector4(0.0, 0.0, 1.0, 1.0) }; static AZ::Vector3 normals[] = { //Front Face AZ::Vector3(0.0, 0.0, 1.0), AZ::Vector3(0.0, 0.0, 1.0), AZ::Vector3(0.0, 0.0, 1.0), AZ::Vector3(0.0, 0.0, 1.0), //Back Face AZ::Vector3(0.0, 0.0,-1.0), AZ::Vector3(0.0, 0.0,-1.0), AZ::Vector3(0.0, 0.0,-1.0), AZ::Vector3(0.0, 0.0,-1.0), //Left Face AZ::Vector3(-1.0, 0.0, 0.0), AZ::Vector3(-1.0, 0.0, 0.0), AZ::Vector3(-1.0, 0.0, 0.0), AZ::Vector3(-1.0, 0.0, 0.0), //Right Face AZ::Vector3(1.0, 0.0, 0.0), AZ::Vector3(1.0, 0.0, 0.0), AZ::Vector3(1.0, 0.0, 0.0), AZ::Vector3(1.0, 0.0, 0.0), //Top Face AZ::Vector3(0.0, 1.0, 0.0), AZ::Vector3(0.0, 1.0, 0.0), AZ::Vector3(0.0, 1.0, 0.0), AZ::Vector3(0.0, 1.0, 0.0), //Bottom Face AZ::Vector3(0.0, -1.0, 0.0), AZ::Vector3(0.0, -1.0, 0.0), AZ::Vector3(0.0, -1.0, 0.0), AZ::Vector3(0.0, -1.0, 0.0) }; static uint16_t indices[] = { //Back 2, 0, 1, 0, 2, 3, //Front 4, 6, 5, 6, 4, 7, //Left 8, 10, 9, 10, 8, 11, //Right 14, 12, 13, 15, 12, 14, //Top 16, 18, 17, 18, 16, 19, //Bottom 22, 20, 21, 23, 20, 22 }; for (int i = 0; i < AZ_ARRAY_SIZE(vertices); ++i) { SetVertexPosition(positionBuffer, i, vertices[i]); if (colorBuffer) { SetVertexColor(colorBuffer, i, colors[i]); } if (normalBuffer) { SetVertexNormal(normalBuffer, i, normals[i]); } } ::memcpy(indexBuffer, indices, sizeof(indices)); } void BasicRHIComponent::SetVertexIndexIncreasing(uint16_t* indexBuffer, size_t bufferSize) { for (int i = 0; i < bufferSize; ++i) { indexBuffer[i] = static_cast(i); } } AZ::Matrix4x4 BasicRHIComponent::CreateViewMatrix(AZ::Vector3 eye, AZ::Vector3 up, AZ::Vector3 lookAt) { AZ::Vector3 zaxis, xaxis, yaxis; zaxis = eye - lookAt; if (!zaxis.IsZero()) { zaxis.Normalize(); } xaxis = up.Cross(zaxis); if (!xaxis.IsZero()) { xaxis.Normalize(); } yaxis = zaxis.Cross(xaxis); AZ::Matrix4x4 result = AZ::Matrix4x4::CreateFromRows ( AZ::Vector4(xaxis.GetX(), xaxis.GetY(), xaxis.GetZ(), -xaxis.Dot(eye)), AZ::Vector4(yaxis.GetX(), yaxis.GetY(), yaxis.GetZ(), -yaxis.Dot(eye)), AZ::Vector4(zaxis.GetX(), zaxis.GetY(), zaxis.GetZ(), -zaxis.Dot(eye)), AZ::Vector4( 0.f, 0.f, 0.f, 1.f) ); return result; } void BasicRHIComponent::FindShaderInputIndex( AZ::RHI::ShaderInputConstantIndex* shaderInputConstIndex, AZ::Data::Instance shaderResourceGroup, const AZ::Name& shaderInputName, [[maybe_unused]] const char* componentName) { *shaderInputConstIndex = shaderResourceGroup->FindShaderInputConstantIndex(shaderInputName); AZ_Error(componentName, shaderInputConstIndex->IsValid(), "Failed to find shader input constant %s.", shaderInputName.GetCStr()); } void BasicRHIComponent::FindShaderInputIndex( AZ::RHI::ShaderInputImageIndex* shaderInputImageIndex, AZ::Data::Instance shaderResourceGroup, const AZ::Name& shaderInputName, [[maybe_unused]] const char* componentName) { *shaderInputImageIndex = shaderResourceGroup->FindShaderInputImageIndex(shaderInputName); AZ_Error(componentName, shaderInputImageIndex->IsValid(), "Failed to find shader input image %s.", shaderInputName.GetCStr()); } void BasicRHIComponent::FindShaderInputIndex( AZ::RHI::ShaderInputBufferIndex* shaderInputBufferIndex, AZ::Data::Instance shaderResourceGroup, const AZ::Name& shaderInputName, [[maybe_unused]] const char* componentName) { *shaderInputBufferIndex = shaderResourceGroup->FindShaderInputBufferIndex(shaderInputName); AZ_Error(componentName, shaderInputBufferIndex->IsValid(), "Failed to find shader input buffer %s.", shaderInputName.GetCStr()); } void BasicRHIComponent::FindShaderInputIndex( AZ::RHI::ShaderInputSamplerIndex* shaderInputSamplerIndex, AZ::Data::Instance shaderResourceGroup, const AZ::Name& shaderInputName, [[maybe_unused]] const char* componentName) { *shaderInputSamplerIndex = shaderResourceGroup->FindShaderInputSamplerIndex(shaderInputName); AZ_Error(componentName, shaderInputSamplerIndex->IsValid(), "Failed to find sampler %s.", shaderInputName.GetCStr()); } AZ::Data::Instance BasicRHIComponent::LoadShader(const char* shaderFilePath, [[maybe_unused]] const char* sampleName, const AZ::Name* supervariantName) { using namespace AZ; Data::AssetId shaderAssetId; Data::AssetCatalogRequestBus::BroadcastResult( shaderAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, shaderFilePath, azrtti_typeid(), false); if (!shaderAssetId.IsValid()) { AZ_Error(sampleName, false, "Failed to get shader asset id with path %s", shaderFilePath); return nullptr; } auto shaderAsset = Data::AssetManager::Instance().GetAsset( shaderAssetId, AZ::Data::AssetLoadBehavior::PreLoad); shaderAsset.BlockUntilLoadComplete(); if (!shaderAsset.IsReady()) { AZ_Error(sampleName, false, "Failed to get shader asset with path %s", shaderFilePath); return nullptr; } auto shader = RPI::Shader::FindOrCreate(shaderAsset, (supervariantName != nullptr) ? *supervariantName : AZ::Name{""}); if (!shader) { AZ_Error(sampleName, false, "Failed to find or create a shader instance from shader asset '%s'", shaderFilePath); return nullptr; } return shader; } AZ::Data::Instance BasicRHIComponent::LoadShader(const AZ::AssetCollectionAsyncLoader& assetLoadMgr, const char* shaderFilePath, [[maybe_unused]] const char* sampleName) { using namespace AZ; auto shaderAsset = assetLoadMgr.GetAsset(shaderFilePath); AZ_Assert(shaderAsset.IsReady(), "Shader asset %s is supposed to be ready", shaderFilePath); auto shader = RPI::Shader::FindOrCreate(shaderAsset); if (!shader) { AZ_Error(sampleName, false, "Failed to find or create a shader instance from shader asset '%s'", shaderFilePath); return nullptr; } return shader; } AZ::Data::Instance BasicRHIComponent::CreateShaderResourceGroup(AZ::Data::Instance shader, const char* shaderResourceGroupId, [[maybe_unused]] const char* sampleName) { auto srg = AZ::RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), AZ::Name { shaderResourceGroupId }); if (!srg) { AZ_Error(sampleName, false, "Failed to create shader resource group"); return nullptr; } return srg; } AZ::Data::Instance BasicRHIComponent::LoadStreamingImage(const char* textureFilePath, [[maybe_unused]] const char* sampleName) { using namespace AZ; Data::AssetId streamingImageAssetId; Data::AssetCatalogRequestBus::BroadcastResult( streamingImageAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, textureFilePath, azrtti_typeid(), false); if (!streamingImageAssetId.IsValid()) { AZ_Error(sampleName, false, "Failed to get streaming image asset id with path %s", textureFilePath); return nullptr; } auto streamingImageAsset = Data::AssetManager::Instance().GetAsset( streamingImageAssetId, AZ::Data::AssetLoadBehavior::PreLoad); streamingImageAsset.BlockUntilLoadComplete(); if (!streamingImageAsset.IsReady()) { AZ_Error(sampleName, false, "Failed to get streaming image asset '%s'", textureFilePath); return nullptr; } auto image = RPI::StreamingImage::FindOrCreate(streamingImageAsset); if (!image) { AZ_Error(sampleName, false, "Failed to find or create an image instance from image asset '%s'", textureFilePath); return nullptr; } return image; } void BasicRHIComponent::CreateImage3dData(AZStd::vector& data, AZ::RHI::ImageSubresourceLayout& layout, AZ::RHI::Format& format, AZStd::vector&& imageAssetPaths) { using namespace AZ; const auto getStreamingImageAsset = [](const char* path) -> AZ::Data::Asset { Data::AssetId streamingImageAssetId; Data::AssetCatalogRequestBus::BroadcastResult( streamingImageAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, path, azrtti_typeid(), false); AZ::Data::Asset streamingImageAsset = Data::AssetManager::Instance().GetAsset( streamingImageAssetId, AZ::Data::AssetLoadBehavior::PreLoad); streamingImageAsset.BlockUntilLoadComplete(); return streamingImageAsset; }; AZStd::vector imageDescriptors; imageDescriptors.reserve(imageAssetPaths.size()); AZStd::vector imageSubresourceLayouts; imageSubresourceLayouts.reserve(imageAssetPaths.size()); AZStd::vector> imageMipAssets; imageMipAssets.reserve(imageAssetPaths.size()); // Load the first mip of the images for (const char* imageAssetPath : imageAssetPaths) { Data::Asset streamingImageAsset = getStreamingImageAsset(imageAssetPath); RHI::ImageDescriptor imageDescriptor = streamingImageAsset->GetImageDescriptor(); imageDescriptors.emplace_back(imageDescriptor); // Load the mip Data::Asset mipAsset = streamingImageAsset->GetMipChainAsset(0); mipAsset = Data::AssetManager::Instance().GetAsset( mipAsset.GetId(), AZ::Data::AssetLoadBehavior::PreLoad); mipAsset.BlockUntilLoadComplete(); imageMipAssets.emplace_back(mipAsset); const RHI::ImageSubresourceLayout subImageLayout = mipAsset->GetSubImageLayout(0); imageSubresourceLayouts.emplace_back(subImageLayout); } // Validate the compatibility of the image sub resources for (uint32_t i = 1; i < imageSubresourceLayouts.size(); i++) { [[maybe_unused]] const bool compatibleFormat = imageDescriptors[0].m_format == imageDescriptors[i].m_format; [[maybe_unused]] const bool compatibleLayout = imageSubresourceLayouts[0].m_size == imageSubresourceLayouts[i].m_size && imageSubresourceLayouts[0].m_rowCount == imageSubresourceLayouts[i].m_rowCount && imageSubresourceLayouts[0].m_bytesPerRow == imageSubresourceLayouts[i].m_bytesPerRow && imageSubresourceLayouts[0].m_bytesPerImage == imageSubresourceLayouts[i].m_bytesPerImage; AZ_Assert(compatibleLayout && compatibleFormat, "The image sub resources of the first MIP aren't compatible."); } // Allocate the data of the first mip of the images sequentially const uint32_t bytesPerImage = imageSubresourceLayouts[0].m_bytesPerImage; data.resize(imageSubresourceLayouts[0].m_bytesPerImage * imageSubresourceLayouts.size()); for (uint32_t i = 0; i < imageMipAssets.size(); i++) { const uint64_t dataOffset = i * bytesPerImage; memcpy(static_cast(data.data()) + dataOffset, imageMipAssets[i]->GetSubImageData(0).data(), imageSubresourceLayouts[0].m_bytesPerImage); } format = imageDescriptors[0].m_format; layout = imageSubresourceLayouts[0]; layout.m_size.m_depth = static_cast(imageAssetPaths.size()); } void BasicRHIComponent::SetOutputInfo(uint32_t width, uint32_t height, AZ::RHI::Format format, AZ::RHI::AttachmentId attachmentId) { m_outputWidth = width; m_outputHeight = height; m_outputFormat = format; m_outputAttachmentId = attachmentId; UpdateViewportAndScissor(); } void BasicRHIComponent::SetOutputInfoFromWindowContext() { m_outputFormat = m_windowContext->GetSwapChain()->GetDescriptor().m_dimensions.m_imageFormat; m_outputWidth = aznumeric_cast(m_windowContext->GetViewport().m_maxX - m_windowContext->GetViewport().m_minX); m_outputHeight = aznumeric_cast(m_windowContext->GetViewport().m_maxY - m_windowContext->GetViewport().m_minY); m_outputAttachmentId = m_windowContext->GetSwapChain()->GetAttachmentId(); UpdateViewportAndScissor(); } void BasicRHIComponent::UpdateViewportAndScissor() { m_viewport = AZ::RHI::Viewport(0, aznumeric_cast(m_outputWidth), 0, aznumeric_cast(m_outputHeight)); m_scissor = AZ::RHI::Scissor(0, 0, m_outputWidth, m_outputHeight); } bool BasicRHIComponent::IsSupportedRHISamplePipeline() { return m_supportRHISamplePipeline; } float BasicRHIComponent::GetViewportWidth() { return m_viewport.m_maxX - m_viewport.m_minX; } float BasicRHIComponent::GetViewportHeight() { return m_viewport.m_maxY - m_viewport.m_minY; } void BasicRHIComponent::SetViewIndex(const uint32_t viewIndex) { m_viewIndex = viewIndex; } }