123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- /*
- * 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 <Atom/RHI/DrawPacket.h>
- #include <Atom/RHI/DrawPacketBuilder.h>
- #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
- #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
- #include <Atom/RPI.Public/Image/StreamingImagePool.h>
- #include <Atom/RPI.Public/Image/StreamingImageController.h>
- #include <Atom/RPI.Public/RPISystemInterface.h>
- #include <Atom/RPI.Public/Scene.h>
- #include <Atom/RPI.Public/Shader/Shader.h>
- #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
- #include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
- #include <Automation/ScriptableImGui.h>
- #include <Automation/ScriptRunnerBus.h>
- #include <AzCore/Asset/AssetManagerBus.h>
- #include <AzCore/IO/FileIO.h>
- #include <AzCore/IO/SystemFile.h>
- #include <AzCore/std/time.h>
- #include <AzCore/Utils/Utils.h>
- #include <AzFramework/API/ApplicationAPI.h>
- #include <RHI/BasicRHIComponent.h>
- #include <SampleComponentConfig.h>
- #include <StreamingImageExampleComponent.h>
- namespace AtomSampleViewer
- {
- using namespace AZ;
- void StreamingImageExampleComponent::Reflect(ReflectContext* context)
- {
- if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
- {
- serializeContext->Class < StreamingImageExampleComponent, Component>()
- ->Version(0)
- ;
- }
- }
- void StreamingImageExampleComponent::PrepareRenderData()
- {
- const auto CreatePipeline = [](const char* shaderFilepath,
- const char* srgName,
- Data::Asset<AZ::RPI::ShaderAsset>& shaderAsset,
- RHI::Ptr<AZ::RHI::ShaderResourceGroupLayout>& srgLayout,
- RHI::ConstPtr<RHI::PipelineState>& pipelineState,
- RHI::DrawListTag& drawListTag,
- RPI::Scene* scene)
- {
- // Since the shader is using SV_VertexID and SV_InstanceID as VS input, we won't need to have vertex buffer.
- // Also, the index buffer is not needed with DrawLinear.
- RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
- shaderAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::ShaderAsset>(shaderFilepath, RPI::AssetUtils::TraceLevel::Error);
- Data::Instance<RPI::Shader> shader = RPI::Shader::FindOrCreate(shaderAsset);
- if (!shader)
- {
- AZ_Error("Render", false, "Failed to find or create shader instance from shader asset with path %s", shaderFilepath);
- return;
- }
- const RPI::ShaderVariant& shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
- shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
- drawListTag = shader->GetDrawListTag();
- scene->ConfigurePipelineState(shader->GetDrawListTag(), pipelineStateDescriptor);
- pipelineStateDescriptor.m_inputStreamLayout.SetTopology(AZ::RHI::PrimitiveTopology::TriangleStrip);
- pipelineStateDescriptor.m_inputStreamLayout.Finalize();
- pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor);
- if (!pipelineState)
- {
- AZ_Error("Render", false, "Failed to acquire default pipeline state for shader %s", shaderFilepath);
- }
- // Load shader resource group layout
- srgLayout = shaderAsset->FindShaderResourceGroupLayout(AZ::Name(srgName));
- };
- // Create the example's main pipeline object
- {
- CreatePipeline("Shaders/streamingimageexample/imagemips.azshader", "ImageMipsSrg", m_shaderAsset, m_srgLayout, m_pipelineState, m_drawListTag, m_scene);
- // Set the input indices
- m_imageInputIndex = m_srgLayout->FindShaderInputImageIndex(Name("m_texture"));
- m_positionInputIndex = m_srgLayout->FindShaderInputConstantIndex(Name("m_position"));
- m_sizeInputIndex = m_srgLayout->FindShaderInputConstantIndex(Name("m_size"));
- m_residentMipInputIndex = m_srgLayout->FindShaderInputConstantIndex(Name("m_residentMip"));
- // Create an SRG instance for the hot reloaded image
- m_imageHotReload.m_srg = RPI::ShaderResourceGroup::Create(m_shaderAsset, m_srgLayout->GetName());
- }
- // Create the 3D pipeline object
- {
- CreatePipeline("Shaders/streamingimageexample/image3d.azshader", "ImageSrg", m_image3dShaderAsset, m_image3dSrgLayout, m_image3dPipelineState,
- m_image3dDrawListTag, m_scene);
- }
- }
- void StreamingImageExampleComponent::Activate()
- {
- // Save the streaming image pool's budget and streaming image pool controller's mip bias
- // These would be recovered when exist the example
- Data::Instance<RPI::StreamingImagePool> streamingImagePool = RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
- m_cachedPoolBudget = streamingImagePool->GetMemoryBudget();
- m_cachedMipBias = streamingImagePool->GetMipBias();
- m_enableHotReloadTest = IsHotReloadTestSupported();
- m_dynamicDraw = RPI::GetDynamicDraw();
- m_imguiSidebar.Activate();
- PrepareRenderData();
- if (m_enableHotReloadTest)
- {
- DeleteHotReloadImage();
- }
- m_loadImageStart = AZStd::GetTimeUTCMilliSecond();
- // Queue load all the textures under Textures\Streaming folder
- for (uint32_t index = 0; index < TestDDSCount; index++)
- {
- AZ::IO::Path filePath = TestImageFolder / AZStd::string::format("streaming%d.dds.streamingimage", index);
- QueueForLoad(filePath.Native());
- }
- // All Images loaded here have non-power-of-two sizes
- for (uint32_t index = 0; index < TestPNGCount; index++)
- {
- AZ::IO::Path filePath = TestImageFolder / AZStd::string::format("streaming%d.png.streamingimage", index);
- QueueForLoad(filePath.Native());
- }
- AZ::TickBus::Handler::BusConnect();
- if (m_enableHotReloadTest)
- {
- AzFramework::AssetCatalogEventBus::Handler::BusConnect();
- SwitchHotReloadImage();
- }
- // Pause lua script (automation) until all the images loaded
- // Use a 10 seconds timeout instead of default one in case of longer loading time
- ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 10.0f);
- m_automationPaused = true;
- }
- void StreamingImageExampleComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
- {
- // Skip processing if the asset is the asset for hot reloading test
- // The original asset was already processed.
- if (m_reloadingAsset == asset.GetId())
- {
- return;
- }
- AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());;
- const float ratioYtoX = 1.0f;
- // Create the image for hot reload test and setup its srg for draw
- if (m_imageHotReload.m_assetId == asset.GetId())
- {
- m_imageHotReload.m_image = AZ::RPI::StreamingImage::FindOrCreate(asset);
- m_imageHotReload.m_srg->SetImage(m_imageInputIndex, m_imageHotReload.m_image);
- AZStd::array<float, 2> position{
- { 0.33f, 0.22f }
- };
- AZStd::array<float, 2> size{
- { 0.2f, 0.2f / ratioYtoX }
- };
- m_imageHotReload.m_srg->SetConstant(m_positionInputIndex, position);
- m_imageHotReload.m_srg->SetConstant(m_sizeInputIndex, size);
- m_imageHotReload.m_srg->SetConstant(m_residentMipInputIndex, static_cast<int>(m_imageHotReload.m_image->GetResidentMipLevel()));
- // Note: no need to queue the srg for compile since the OnTick would compile it anyway
- return;
- }
- auto iter = AZStd::find_if(m_images.begin(), m_images.end(), [&asset](const ImageToDraw& image)
- {
- return image.m_assetId == asset.GetId();
- });
- if (iter == m_images.end())
- {
- return;
- }
- ImageToDraw* imageToDraw = iter;
- ptrdiff_t index = AZStd::distance(m_images.begin(), iter);
- AZ::u64 startTime = AZStd::GetTimeUTCMilliSecond();
- imageToDraw->m_image = AZ::RPI::StreamingImage::FindOrCreate(asset);
- AZ::u64 endTime = AZStd::GetTimeUTCMilliSecond();
- m_createImageTime += endTime - startTime;
- AZ::Data::AssetInfo info;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(info, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, imageToDraw->m_image->GetAssetId());
- m_initialImageAssetSize += info.m_sizeBytes;
- imageToDraw->m_srg->SetImage(m_imageInputIndex, imageToDraw->m_image);
- size_t rows = 6;
- size_t columns = (m_images.size() + rows - 1) / rows;
- float xOffset = AreaWidth / columns;
- float yOffset = AreaHeight / rows;
- AZStd::array<float, 2> mipSize;
- if (yOffset * ratioYtoX > xOffset / 1.5f) // the xOffset should be 1.5 times of mip size so it can show lower mips
- {
- mipSize[0] = xOffset / 1.5f;
- mipSize[1] = mipSize[0] / ratioYtoX;
- }
- else
- {
- mipSize[0] = yOffset * ratioYtoX;
- mipSize[1] = yOffset;
- }
- AZStd::array<float, 2> position;
- position[0] = (index / rows) * xOffset + AreaLeft;
- position[1] = (index % rows) * yOffset + AreaBottom;
- imageToDraw->m_srg->SetConstant(m_positionInputIndex, position);
- imageToDraw->m_srg->SetConstant(m_sizeInputIndex, mipSize);
- imageToDraw->m_srg->SetConstant<int>(m_residentMipInputIndex, imageToDraw->m_image->GetResidentMipLevel());
- // no need to queue for compile since the OnTick would compile it anyway
- m_numImageCreated++;
- if (m_numImageAssetQueued == m_numImageCreated)
- {
- // All images created.
- m_loadImageEnd = AZStd::GetTimeUTCMilliSecond();
- }
- }
- void StreamingImageExampleComponent::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
- {
- if (m_reloadingAsset == asset.GetId())
- {
- m_reloadingAsset.SetInvalid();
- AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
- }
- }
- void StreamingImageExampleComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
- {
- OnCatalogAssetAdded(assetId);
- }
- void StreamingImageExampleComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
- {
- if (!m_imageHotReload.m_assetId.IsValid())
- {
- AZ::IO::Path filePath = TestImageFolder / (ReloadTestImageName.Native() + ".streamingimage");
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(
- m_imageHotReload.m_assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, filePath.c_str(),
- azrtti_typeid <AZ::RPI::StreamingImageAsset>(), false);
- }
- if (m_imageHotReload.m_assetId == assetId)
- {
- m_imageHotReload.m_asset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::StreamingImageAsset>(assetId, AZ::Data::AssetLoadBehavior::PreLoad);
- AZ::Data::AssetBus::MultiHandler::BusConnect(assetId);
- AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
- }
- }
- void StreamingImageExampleComponent::Deactivate()
- {
- if (AzFramework::AssetCatalogEventBus::Handler::BusIsConnected())
- {
- AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
- }
- AZ::TickBus::Handler::BusDisconnect();
- // If there are any assets that haven't finished loading yet, and thus haven't been disconnected, disconnect now.
- AZ::Data::AssetBus::MultiHandler::BusDisconnect();
- if (m_enableHotReloadTest)
- {
- DeleteHotReloadImage();
- }
- m_imguiSidebar.Deactivate();
- m_images.clear();
- m_numImageAssetQueued = 0;
- m_numImageCreated = 0;
- m_imageHotReload.Reset();
- m_pipelineState = nullptr;
- m_drawListTag.Reset();
- m_shaderAsset = {};
- m_srgLayout = nullptr;
- m_3dImages.clear();
- m_image3dShaderAsset = {};
- m_image3dSrgLayout = nullptr;
- m_image3dPipelineState = nullptr;
- m_image3dDrawListTag.Reset();
- // Recover pool budget and mip bias
- Data::Instance<RPI::StreamingImagePool> streamingImagePool = RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
- streamingImagePool->SetMemoryBudget(m_cachedPoolBudget);
- streamingImagePool->SetMipBias(m_cachedMipBias);
- }
- void StreamingImageExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
- {
- // update image streaming states
- uint32_t numStreamed = 0;
- for (auto& imageInfo : m_images)
- {
- if (imageInfo.m_image)
- {
- imageInfo.m_srg->SetConstant<int>(m_residentMipInputIndex, imageInfo.m_image->GetResidentMipLevel());
- imageInfo.m_srg->Compile();
- if (imageInfo.m_image->IsStreamed())
- {
- numStreamed ++;
- }
- }
- }
- // only need to set the image the first time all images were streamed
- if (m_streamingImageEnd == 0 && numStreamed == m_numImageCreated && m_numImageCreated > 0 && m_numImageAssetQueued == m_numImageCreated)
- {
- m_streamingImageEnd = AZStd::GetTimeUTCMilliSecond();
- for (auto& imageInfo : m_images)
- {
- m_imageAssetSize += GetImageAssetSize(imageInfo.m_image.get());
- }
- }
- if (m_imageHotReload.m_image)
- {
- m_imageHotReload.m_srg->SetConstant<int>(m_residentMipInputIndex, m_imageHotReload.m_image->GetResidentMipLevel());
- m_imageHotReload.m_srg->Compile();
- }
- bool streamingFinished = m_streamingImageEnd > 0;
- // Resume automation when all image streamed and hot reload finished
- if (m_automationPaused && streamingFinished && m_imageHotReload.m_image && m_imageHotReload.m_image->IsStreamed() && !m_reloadingAsset.IsValid())
- {
- ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
- m_automationPaused = false;
- }
- if (m_imguiSidebar.Begin())
- {
- Data::Instance<RPI::StreamingImagePool> streamingImagePool = RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
- const RHI::StreamingImagePool* rhiPool = streamingImagePool->GetRHIPool();
- const RHI::HeapMemoryUsage& memoryUsage = rhiPool->GetHeapMemoryUsage(RHI::HeapMemoryLevel::Device);
- const size_t MB = 1024*1024;
- // streaming image pool info
- ImGui::BeginGroup();
- ImGui::Text("Streaming image pool");
- ImGui::Indent();
- ImGui::Text("Image count: %u", streamingImagePool->GetImageCount());
- ImGui::Text("Streamable image count: %u", streamingImagePool->GetStreamableImageCount());
- size_t totalResident = memoryUsage.m_totalResidentInBytes.load();
- ImGui::Text("Allocated GPU memory: %zu MB (%zu)", totalResident/MB, totalResident);
- size_t usedResident = memoryUsage.m_usedResidentInBytes.load();
- ImGui::Text("Used GPU memory: %zu MB (%zu)", usedResident/MB, usedResident);
-
- size_t budgetInBytes = memoryUsage.m_budgetInBytes;
- int budgetInMB = aznumeric_cast<int>(budgetInBytes/MB);
- ImGui::Text("GPU memory budget: %d MB", budgetInMB);
- if (ScriptableImGui::SliderInt("MB", &budgetInMB, RHI::StreamingImagePool::ImagePoolMininumSizeInBytes/MB, 512))
- {
- streamingImagePool->SetMemoryBudget(budgetInMB * (1024*1024));
- }
- int mipBias = streamingImagePool->GetMipBias();
- ImGui::Text("Mip bias");
- if (ScriptableImGui::SliderInt("", &mipBias, -aznumeric_cast<int>(RHI::Limits::Image::MipCountMax), RHI::Limits::Image::MipCountMax))
- {
- streamingImagePool->SetMipBias(aznumeric_cast<int16_t>(mipBias));
- }
- ImGui::Unindent();
- ImGui::EndGroup();
- // Draw menus and info when streaming is finished
- if (streamingFinished)
- {
- // For switching rendering content between streamed images or 3d images
- ImGui::Text("Image type view");
- ImGui::Indent();
- const char* buttonLabel = m_viewStreamedImages ? "View 3D Images" : "View Streamed Images";
- if (ScriptableImGui::Button(buttonLabel))
- {
- m_viewStreamedImages = !m_viewStreamedImages;
- }
- ImGui::Unindent();
- ImGui::Separator();
- ImGui::NewLine();
- // For StreamingImageAsset hot reloading test
- ImGui::Text("Hot Reload Test");
- ImGui::Indent();
- if (m_enableHotReloadTest && m_imageHotReload.m_image && m_imageHotReload.m_image->IsStreamed())
- {
- if (ScriptableImGui::Button("Switch texture"))
- {
- SwitchHotReloadImage();
- ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 10.0f);
- m_automationPaused = true;
- m_reloadingAsset = m_imageHotReload.m_assetId;
- AZ::Data::AssetBus::MultiHandler::BusConnect(m_reloadingAsset);
- }
- }
- ImGui::Unindent();
- // Display streaming profile result
- ImGui::Separator();
- ImGui::NewLine();
- DisplayStreamingProfileData();
- }
- m_imguiSidebar.End();
- }
- if (m_viewStreamedImages)
- {
- DrawImages();
- }
- else
- {
- if (m_3dImages.size() == 0)
- {
- Create3dimages();
- if (m_3dImages.size() == 0)
- {
- m_viewStreamedImages = true;
- return;
- }
- }
- Draw3dImages();
- }
- }
- void StreamingImageExampleComponent::DrawImages()
- {
- for (auto& imageInfo : m_images)
- {
- if (imageInfo.m_image != nullptr)
- {
- DrawImage(&imageInfo);
- }
- }
- if (m_imageHotReload.m_image != nullptr)
- {
- DrawImage(&m_imageHotReload);
- }
- }
- void StreamingImageExampleComponent::Draw3dImages()
- {
- for (Image3dToDraw& image3d : m_3dImages)
- {
- // Build draw packet...
- RHI::DrawPacketBuilder drawPacketBuilder;
- drawPacketBuilder.Begin(nullptr);
- RHI::DrawLinear drawLinear;
- drawLinear.m_vertexCount = 4;
- drawLinear.m_instanceCount = image3d.m_sliceCount;
- drawPacketBuilder.SetDrawArguments(drawLinear);
- RHI::DrawPacketBuilder::DrawRequest drawRequest;
- drawRequest.m_listTag = m_image3dDrawListTag;
- drawRequest.m_pipelineState = m_image3dPipelineState.get();
- drawRequest.m_sortKey = 0;
- drawRequest.m_uniqueShaderResourceGroup = image3d.m_srg->GetRHIShaderResourceGroup();
- drawPacketBuilder.AddDrawItem(drawRequest);
- // Submit draw packet...
- AZStd::unique_ptr<const RHI::DrawPacket> drawPacket(drawPacketBuilder.End());
- m_dynamicDraw->AddDrawPacket(m_scene, AZStd::move(drawPacket));
- }
- }
- void StreamingImageExampleComponent::DrawImage(const ImageToDraw* imageInfo)
- {
- // Build draw packet...
- RHI::DrawPacketBuilder drawPacketBuilder;
- drawPacketBuilder.Begin(nullptr);
- RHI::DrawLinear drawLinear;
- drawLinear.m_vertexCount = 4;
- drawLinear.m_instanceCount = imageInfo->m_image->GetMipLevelCount();
- drawPacketBuilder.SetDrawArguments(drawLinear);
- RHI::DrawPacketBuilder::DrawRequest drawRequest;
- drawRequest.m_listTag = m_drawListTag;
- drawRequest.m_pipelineState = m_pipelineState.get();
- drawRequest.m_sortKey = 0;
- drawRequest.m_uniqueShaderResourceGroup = imageInfo->m_srg->GetRHIShaderResourceGroup();
- drawPacketBuilder.AddDrawItem(drawRequest);
- // Submit draw packet...
- AZStd::unique_ptr<const RHI::DrawPacket> drawPacket(drawPacketBuilder.End());
- m_dynamicDraw->AddDrawPacket(m_scene, AZStd::move(drawPacket));
- }
- void StreamingImageExampleComponent::DisplayStreamingProfileData()
- {
- ImGui::BeginGroup();
- ImGui::Text("Streaming Profile");
- ImGui::Indent();
- ImGui::Text("Streaming Image Count: %d", m_numImageCreated);
- ImGui::Text("Load and Create Images: %llu ms", m_loadImageEnd - m_loadImageStart);
- ImGui::Text("Create Images: %llu ms", m_createImageTime);
- ImGui::Text("Streaming Image Mips: %llu ms", m_streamingImageEnd - m_loadImageEnd);
- ImGui::Text("Initial image asset size: %.3f MB", m_initialImageAssetSize / (1024 * 1024.0f));
- ImGui::Text("Total image asset size: %.3f MB", m_imageAssetSize / (1024 * 1024.0f));
- ImGui::Unindent();
- ImGui::EndGroup();
- }
- bool StreamingImageExampleComponent::CopyFile(const AZStd::string& destFile, const AZStd::string& sourceFile)
- {
- IO::FileIOStream fileRead(sourceFile.c_str(), IO::OpenMode::ModeRead | IO::OpenMode::ModeBinary);
- IO::FileIOStream fileWrite(destFile.c_str(), IO::OpenMode::ModeWrite | IO::OpenMode::ModeCreatePath | IO::OpenMode::ModeBinary);
- if (!fileRead.IsOpen() || !fileWrite.IsOpen())
- {
- AZ_Assert(fileRead.IsOpen(), "Failed to open file [%s] for read", sourceFile.c_str());
- AZ_Assert(fileWrite.IsOpen(), "Failed to open file [%s] for write", destFile.c_str());
- return false;
- }
- auto fileLength = fileRead.GetLength();
- AZStd::vector<u8> buffer;
- buffer.resize_no_construct(fileLength);
- fileRead.Read(fileLength, buffer.data());
- fileWrite.Write(fileLength, buffer.data());
- return true;
- }
- void StreamingImageExampleComponent::SwitchHotReloadImage()
- {
- m_curSourceImage = 1 - m_curSourceImage;
- // uses smaller size images for the hot reloading test so the lua automation test won't take very long time
- AZStd::string sourceImageFiles[] = {
- {"streaming1.png"}, {"streaming2.png" }
- };
- AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
- AZ::IO::FixedMaxPath srcPath = projectPath / TestImageFolder / sourceImageFiles[m_curSourceImage];
- AZ::IO::FixedMaxPath destPath = projectPath / TestImageFolder / ReloadTestImageName;
- CopyFile(destPath.String(), srcPath.String());
- }
- void StreamingImageExampleComponent::DeleteHotReloadImage()
- {
- const auto testFileFullPath = AZ::IO::FixedMaxPath(AZ::Utils::GetProjectPath()) / TestImageFolder / ReloadTestImageName;
- if (AZ::IO::SystemFile::Exists(testFileFullPath.c_str()))
- {
- AZ::IO::SystemFile::Delete(testFileFullPath.c_str());
- }
- }
- u64 StreamingImageExampleComponent::GetImageAssetSize(AZ::RPI::StreamingImage* image)
- {
- u64 totalSize = 0;
- AZ::Data::AssetInfo info;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(info, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, image->GetAssetId());
- totalSize += info.m_sizeBytes;
- AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, image->GetAssetId());
- if (result.IsSuccess())
- {
- auto& dependencies = result.GetValue();
- for (const auto& dependency : dependencies)
- {
- info.m_sizeBytes = 0;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(info, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, dependency.m_assetId);
- if (info.m_assetType == azrtti_typeid<RPI::ImageMipChainAsset>())
- {
- totalSize += info.m_sizeBytes;
- }
- }
- }
- return totalSize;
- }
- void StreamingImageExampleComponent::QueueForLoad(const AZStd::string& filePath)
- {
- AZ::Data::AssetId imageAssetId;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(
- imageAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, filePath.c_str(),
- azrtti_typeid <AZ::RPI::StreamingImageAsset>(), false);
- AZ_Assert(imageAssetId.IsValid(), "Unable to load file %s", filePath.c_str());
- if (imageAssetId.IsValid())
- {
- m_numImageAssetQueued++;
- ImageToDraw img;
- img.m_asset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::StreamingImageAsset>(imageAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
- img.m_srg = RPI::ShaderResourceGroup::Create(m_shaderAsset, m_srgLayout->GetName());
- img.m_assetId = imageAssetId;
- m_images.push_back(img);
- AZ::Data::AssetBus::MultiHandler::BusConnect(imageAssetId);
- }
- }
- void StreamingImageExampleComponent::Create3dimages()
- {
- // Use this pool to create the streaming images from
- const Data::Instance<RPI::StreamingImagePool>& imagePool = RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
- // Fetch the shader input indices
- const RHI::ShaderInputImageIndex image3DInputIndex = m_image3dSrgLayout->FindShaderInputImageIndex(Name("m_texture3D"));
- const RHI::ShaderInputConstantIndex sliceCountInputIndex = m_image3dSrgLayout->FindShaderInputConstantIndex(Name("m_sliceCount"));
- const RHI::ShaderInputConstantIndex positionInputIndex = m_image3dSrgLayout->FindShaderInputConstantIndex(Name("m_position"));
- const RHI::ShaderInputConstantIndex sizeInputIndex = m_image3dSrgLayout->FindShaderInputConstantIndex(Name("m_size"));
- // Create a small 3D image, where the row count of an image isn't the same as the height (e.g BC formats). A single slice of the image
- // will be uploaded with a single command
- {
- AZStd::vector<uint8_t> imageData;
- RHI::ImageSubresourceLayout layout;
- RHI::Format format = {};
- BasicRHIComponent::CreateImage3dData(imageData, layout, format, {
- "textures/streaming/streaming13.dds.streamingimage",
- "textures/streaming/streaming14.dds.streamingimage",
- "textures/streaming/streaming15.dds.streamingimage",
- "textures/streaming/streaming16.dds.streamingimage",
- "textures/streaming/streaming17.dds.streamingimage",
- "textures/streaming/streaming19.dds.streamingimage",
- "textures/streaming/streaming20.dds.streamingimage" });
- auto image = RPI::StreamingImage::CreateFromCpuData(*imagePool.get(),
- RHI::ImageDimension::Image3D,
- layout.m_size,
- format, imageData.data(), imageData.size());
- // The image may not be created successfully if the memory budget was set to a very low value
- if (image)
- {
- // Create the srg
- Image3dToDraw image3d;
- image3d.m_srg = RPI::ShaderResourceGroup::Create(m_image3dShaderAsset, m_image3dSrgLayout->GetName());
- image3d.m_srg->SetImage(image3DInputIndex, image.get(), 0);
- image3d.m_sliceCount = layout.m_size.m_depth;
- m_3dImages.emplace_back(image3d);
- }
- };
- // Create large 3D images, where a single image slice is staged/uploaded with multiple commands
- {
- struct V4u32
- {
- float x, y, z, w;
- };
- const auto createColorImageData = [](V4u32 color, uint32_t width, uint32_t height, AZStd::vector<uint8_t>& data)
- {
- const uint32_t imageSize = width * height * sizeof(color);
- data.resize(data.size() + imageSize);
- V4u32* sourceData = reinterpret_cast<V4u32*>(data.data() + data.size() - imageSize);
- for (uint32_t y = 0; y < height; y++)
- {
- for (uint32_t x = 0; x < width; x++)
- {
- memcpy(sourceData, &color, sizeof(color));
- sourceData++;
- }
- }
- };
- AZStd::vector<uint8_t> imageData;
- const uint32_t side = 1001;
- const uint32_t depth = 3;
- createColorImageData({ 1.0f,0.0f,0.0f,0.0f }, side, side, imageData);
- createColorImageData({ 0.0f,1.0f,0.0f,0.0f }, side, side, imageData);
- createColorImageData({ 0.0f,0.0f,1.0f,0.0f }, side, side, imageData);
- auto image = RPI::StreamingImage::CreateFromCpuData(*imagePool.get(),
- RHI::ImageDimension::Image3D,
- RHI::Size(side, side, depth),
- RHI::Format::R32G32B32A32_FLOAT, imageData.data(), imageData.size());
- // Create the srg
- Image3dToDraw image3d;
- image3d.m_srg = RPI::ShaderResourceGroup::Create(m_image3dShaderAsset, m_image3dSrgLayout->GetName());
- image3d.m_srg->SetImage(image3DInputIndex, image.get(), 0);
- image3d.m_sliceCount = depth;
- m_3dImages.emplace_back(image3d);
- }
- // Set the constants for all 3d images
- {
- // Rendering area, use the same surface area of the streaming images
- const float ratioYtoX = 1;
- const float seam = 0.01f;
- const uint32_t rows = 6;
- for (uint32_t i = 0; i < m_3dImages.size(); i++)
- {
- Image3dToDraw& image3d = m_3dImages[i];
- const uint32_t columns = image3d.m_sliceCount;
- // Calculate the size
- const float xOffset = AreaWidth / static_cast<float>(columns);
- const float yOffset = AreaHeight / static_cast<float>(rows);
- const float minSize = AZStd::min(xOffset, yOffset);
- const AZStd::array<float, 2> size = { {minSize * ratioYtoX, minSize } };
- // Calculate the position
- AZStd::array<float, 2> position;
- position[0] = AreaLeft;
- position[1] = static_cast<float>(i) * (yOffset + seam) + AreaBottom;
- image3d.m_srg->SetConstant<uint32_t>(sliceCountInputIndex, image3d.m_sliceCount);
- image3d.m_srg->SetConstant(positionInputIndex, position);
- image3d.m_srg->SetConstant(sizeInputIndex, size);
- image3d.m_srg->Compile();
- }
- }
- }
- }
|