diff --git a/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.cpp b/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.cpp index f2ff15a16..580f6a191 100644 --- a/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.cpp +++ b/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.cpp @@ -121,6 +121,45 @@ void GraphicsBenchmarkApp::InitKnobs() pFullscreenQuadsSingleRenderpass->SetDisplayName("Single Renderpass"); pFullscreenQuadsSingleRenderpass->SetFlagDescription("Render all fullscreen quads (see --fullscreen-quads-count) in a single renderpass."); pFullscreenQuadsSingleRenderpass->SetIndent(1); + + GetKnobManager().InitKnob(&pRenderOffscreen, "offscreen-render", false); + pRenderOffscreen->SetDisplayName("Offscreen render"); + pRenderOffscreen->SetFlagDescription("Enable render to a offscreen/non-swapchain framebuffer."); + + GetKnobManager().InitKnob(&pBlitOffscreen, "offscreen-blit-to-swapchain", true); + pBlitOffscreen->SetDisplayName("Blit to swapchain"); + pBlitOffscreen->SetFlagDescription("Blit offscreen render result to swapchain."); + pBlitOffscreen->SetIndent(1); + + std::array formatNames; + for (int i = 0; i < std::size(kFramebufferFormatTypes); ++i) { + formatNames[i] = ToString(kFramebufferFormatTypes[i]); + } + formatNames[0] = "Swapchain"; + GetKnobManager().InitKnob(&pFramebufferFormat, "offscreen-framebuffer-format", 0, formatNames); + pFramebufferFormat->SetDisplayName("Framebuffer format"); + pFramebufferFormat->SetFlagDescription("Select the pixel format used in offscreen framebuffer."); + pFramebufferFormat->SetIndent(1); + + std::vector resolutionString; + mResolutionOptions.push_back(std::pair(0, 0)); // Swapchain native + resolutionString.push_back("Swapchain"); + for (const auto& res : kSimpleResolutions) { + mResolutionOptions.push_back(res); + resolutionString.push_back(std::to_string(res.first) + "x" + std::to_string(res.second)); + } + for (const auto& res : kCommonResolutions) { + mResolutionOptions.push_back(res); + resolutionString.push_back(std::to_string(res.first) + "x" + std::to_string(res.second)); + } + for (const auto& res : kVRPerEyeResolutions) { + mResolutionOptions.push_back(std::pair(res.first * 2, res.second)); + resolutionString.push_back(std::to_string(res.first) + "x2" + "x" + std::to_string(res.second)); + } + GetKnobManager().InitKnob(&pResolution, "offscreen-resolution", 0, resolutionString); + pResolution->SetDisplayName("Framebuffer resolution"); + pResolution->SetFlagDescription("Select the size of offscreen framebuffer."); + pResolution->SetIndent(1); } void GraphicsBenchmarkApp::Config(ppx::ApplicationSettings& settings) @@ -171,8 +210,8 @@ void GraphicsBenchmarkApp::Setup() // Descriptor Pool { grfx::DescriptorPoolCreateInfo createInfo = {}; - createInfo.sampler = 4 * GetNumFramesInFlight(); // 1 for skybox, 3 for spheres - createInfo.sampledImage = 5 * GetNumFramesInFlight(); // 1 for skybox, 3 for spheres, 1 for quads + createInfo.sampler = 5 * GetNumFramesInFlight(); // 1 for skybox, 3 for spheres, 1 for blit + createInfo.sampledImage = 6 * GetNumFramesInFlight(); // 1 for skybox, 3 for spheres, 1 for quads, 1 for blit createInfo.uniformBuffer = 2 * GetNumFramesInFlight(); // 1 for skybox, 1 for spheres PPX_CHECKED_CALL(GetDevice()->CreateDescriptorPool(&createInfo, &mDescriptorPool)); @@ -196,6 +235,12 @@ void GraphicsBenchmarkApp::Setup() SetupFullscreenQuadsMeshes(); SetupFullscreenQuadsPipelines(); + // ===================================================================== + // BLIT (DX12 does not have vkCmdBlitImage equivalent) + // ===================================================================== + + PPX_CHECKED_CALL(CreateBlitContext(mBlit)); + // ===================================================================== // PER FRAME DATA // ===================================================================== @@ -231,6 +276,12 @@ void GraphicsBenchmarkApp::Setup() mPerFrame.push_back(frame); } + + { + OffscreenFrame frame = {}; + PPX_CHECKED_CALL(CreateOffscreenFrame(frame, RenderFormat(), GetSwapchain()->GetDepthFormat(), GetSwapchain()->GetWidth(), GetSwapchain()->GetHeight())); + mOffscreenFrame.push_back(frame); + } } void GraphicsBenchmarkApp::SetupSkyBoxResources() @@ -492,6 +543,28 @@ void GraphicsBenchmarkApp::SetupSkyBoxPipelines() piCreateInfo.sets[0].pLayout = mSkyBox.descriptorSetLayout; PPX_CHECKED_CALL(GetDevice()->CreatePipelineInterface(&piCreateInfo, &mSkyBox.pipelineInterface)); + // Pre-load the current pipeline variant. + GetSkyBoxPipeline(); +} + +void GraphicsBenchmarkApp::SetupSpheresPipelines() +{ + grfx::PipelineInterfaceCreateInfo piCreateInfo = {}; + piCreateInfo.setCount = 1; + piCreateInfo.sets[0].set = 0; + piCreateInfo.sets[0].pLayout = mSphere.descriptorSetLayout; + PPX_CHECKED_CALL(GetDevice()->CreatePipelineInterface(&piCreateInfo, &mSphere.pipelineInterface)); + + // Pre-load the current pipeline variant. + GetSpherePipeline(); +} + +Result GraphicsBenchmarkApp::CompilePipeline(const SkyBoxPipelineKey& key) +{ + if (mSkyBoxPipelines.find(key) != mSkyBoxPipelines.end()) { + return SUCCESS; + } + grfx::GraphicsPipelineCreateInfo2 gpCreateInfo = {}; gpCreateInfo.VS = {mVSSkyBox.Get(), "vsmain"}; gpCreateInfo.PS = {mPSSkyBox.Get(), "psmain"}; @@ -505,34 +578,30 @@ void GraphicsBenchmarkApp::SetupSkyBoxPipelines() gpCreateInfo.depthWriteEnable = false; gpCreateInfo.blendModes[0] = grfx::BLEND_MODE_NONE; gpCreateInfo.outputState.renderTargetCount = 1; - gpCreateInfo.outputState.renderTargetFormats[0] = GetSwapchain()->GetColorFormat(); + gpCreateInfo.outputState.renderTargetFormats[0] = key.renderFormat; gpCreateInfo.outputState.depthStencilFormat = GetSwapchain()->GetDepthFormat(); gpCreateInfo.pPipelineInterface = mSkyBox.pipelineInterface; - PPX_CHECKED_CALL(GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &mSkyBox.pipeline)); -} - -void GraphicsBenchmarkApp::SetupSpheresPipelines() -{ - grfx::PipelineInterfaceCreateInfo piCreateInfo = {}; - piCreateInfo.setCount = 1; - piCreateInfo.sets[0].set = 0; - piCreateInfo.sets[0].pLayout = mSphere.descriptorSetLayout; - PPX_CHECKED_CALL(GetDevice()->CreatePipelineInterface(&piCreateInfo, &mSphere.pipelineInterface)); - // Pre-load the current pipeline variant. - GetSpherePipeline(); + grfx::GraphicsPipelinePtr pipeline = nullptr; + Result ppxres = GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &pipeline); + if (ppxres == SUCCESS) { + // Insert a new pipeline to the cache. + // We don't delete old pipeline while we run benchmark + // which require this function to be synchronized to end of frame. + mSkyBoxPipelines[key] = pipeline; + } + return ppxres; } -Result GraphicsBenchmarkApp::CompileSpherePipeline(const SpherePipelineKey& key) +Result GraphicsBenchmarkApp::CompilePipeline(const SpherePipelineKey& key) { if (mPipelines.find(key) != mPipelines.end()) { return SUCCESS; } - grfx::GraphicsPipelinePtr pipeline = nullptr; - bool interleaved = (key.vertexAttributeLayout == 0); - size_t meshIndex = kAvailableVertexAttrLayouts.size() * key.vertexFormat + key.vertexAttributeLayout; - grfx::BlendMode blendMode = (key.enableAlphaBlend ? grfx::BLEND_MODE_ALPHA : grfx::BLEND_MODE_NONE); + bool interleaved = (key.vertexAttributeLayout == 0); + size_t meshIndex = kAvailableVertexAttrLayouts.size() * key.vertexFormat + key.vertexAttributeLayout; + grfx::BlendMode blendMode = (key.enableAlphaBlend ? grfx::BLEND_MODE_ALPHA : grfx::BLEND_MODE_NONE); grfx::GraphicsPipelineCreateInfo2 gpCreateInfo = {}; gpCreateInfo.VS = {mVsShaders[key.vs].Get(), "vsmain"}; @@ -556,11 +625,12 @@ Result GraphicsBenchmarkApp::CompileSpherePipeline(const SpherePipelineKey& key) gpCreateInfo.depthWriteEnable = key.enableDepth; gpCreateInfo.blendModes[0] = blendMode; gpCreateInfo.outputState.renderTargetCount = 1; - gpCreateInfo.outputState.renderTargetFormats[0] = GetSwapchain()->GetColorFormat(); + gpCreateInfo.outputState.renderTargetFormats[0] = key.renderFormat; gpCreateInfo.outputState.depthStencilFormat = GetSwapchain()->GetDepthFormat(); gpCreateInfo.pPipelineInterface = mSphere.pipelineInterface; - Result ppxres = GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &pipeline); + grfx::GraphicsPipelinePtr pipeline = nullptr; + Result ppxres = GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &pipeline); if (ppxres == SUCCESS) { // Insert a new pipeline to the cache. // We don't delete old pipeline while we run benchmark @@ -570,6 +640,37 @@ Result GraphicsBenchmarkApp::CompileSpherePipeline(const SpherePipelineKey& key) return ppxres; } +Result GraphicsBenchmarkApp::CompilePipeline(const QuadPipelineKey& key) +{ + const size_t quadTypeIndex = static_cast(key.quadType); + grfx::GraphicsPipelineCreateInfo2 gpCreateInfo = {}; + gpCreateInfo.VS = {mVSQuads.Get(), "vsmain"}; + gpCreateInfo.PS = {mQuadsPs[quadTypeIndex].Get(), "psmain"}; + gpCreateInfo.vertexInputState.bindingCount = 1; + gpCreateInfo.vertexInputState.bindings[0] = mFullscreenQuads.vertexBinding; + gpCreateInfo.topology = grfx::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + gpCreateInfo.polygonMode = grfx::POLYGON_MODE_FILL; + gpCreateInfo.cullMode = grfx::CULL_MODE_BACK; + gpCreateInfo.frontFace = grfx::FRONT_FACE_CW; + gpCreateInfo.depthReadEnable = false; + gpCreateInfo.depthWriteEnable = false; + gpCreateInfo.blendModes[0] = grfx::BLEND_MODE_NONE; + gpCreateInfo.outputState.renderTargetCount = 1; + gpCreateInfo.outputState.renderTargetFormats[0] = key.renderFormat; + gpCreateInfo.outputState.depthStencilFormat = GetSwapchain()->GetDepthFormat(); + gpCreateInfo.pPipelineInterface = mQuadsPipelineInterfaces[quadTypeIndex]; + + grfx::GraphicsPipelinePtr pipeline = nullptr; + Result ppxres = GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &pipeline); + if (ppxres == SUCCESS) { + // Insert a new pipeline to the cache. + // We don't delete old pipeline while we run benchmark + // which require this function to be synchronized to end of frame. + mQuadsPipelines[key] = pipeline; + } + return ppxres; +} + // Compile or load from cache currently required pipeline. grfx::GraphicsPipelinePtr GraphicsBenchmarkApp::GetSpherePipeline() { @@ -580,10 +681,28 @@ grfx::GraphicsPipelinePtr GraphicsBenchmarkApp::GetSpherePipeline() key.vertexAttributeLayout = static_cast(pKnobVertexAttrLayout->GetIndex()); key.enableDepth = pDepthTestWrite->GetValue(); key.enableAlphaBlend = pAlphaBlend->GetValue(); - PPX_CHECKED_CALL(CompileSpherePipeline(key)); + key.renderFormat = RenderFormat(); + PPX_CHECKED_CALL(CompilePipeline(key)); return mPipelines[key]; } +grfx::GraphicsPipelinePtr GraphicsBenchmarkApp::GetFullscreenQuadPipeline() +{ + QuadPipelineKey key = {}; + key.renderFormat = RenderFormat(); + key.quadType = static_cast(pFullscreenQuadsType->GetIndex()); + PPX_CHECKED_CALL(CompilePipeline(key)); + return mQuadsPipelines[key]; +} + +grfx::GraphicsPipelinePtr GraphicsBenchmarkApp::GetSkyBoxPipeline() +{ + SkyBoxPipelineKey key = {}; + key.renderFormat = RenderFormat(); + PPX_CHECKED_CALL(CompilePipeline(key)); + return mSkyBoxPipelines[key]; +} + void GraphicsBenchmarkApp::SetupFullscreenQuadsPipelines() { // Noise @@ -616,24 +735,23 @@ void GraphicsBenchmarkApp::SetupFullscreenQuadsPipelines() PPX_CHECKED_CALL(GetDevice()->CreatePipelineInterface(&piCreateInfo, &mQuadsPipelineInterfaces[2])); } - for (size_t i = 0; i < kFullscreenQuadsTypes.size(); i++) { - grfx::GraphicsPipelineCreateInfo2 gpCreateInfo = {}; - gpCreateInfo.VS = {mVSQuads.Get(), "vsmain"}; - gpCreateInfo.PS = {mQuadsPs[i].Get(), "psmain"}; - gpCreateInfo.vertexInputState.bindingCount = 1; - gpCreateInfo.vertexInputState.bindings[0] = mFullscreenQuads.vertexBinding; - gpCreateInfo.topology = grfx::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - gpCreateInfo.polygonMode = grfx::POLYGON_MODE_FILL; - gpCreateInfo.cullMode = grfx::CULL_MODE_BACK; - gpCreateInfo.frontFace = grfx::FRONT_FACE_CW; - gpCreateInfo.depthReadEnable = false; - gpCreateInfo.depthWriteEnable = false; - gpCreateInfo.blendModes[0] = grfx::BLEND_MODE_NONE; - gpCreateInfo.outputState.renderTargetCount = 1; - gpCreateInfo.outputState.renderTargetFormats[0] = GetSwapchain()->GetColorFormat(); - gpCreateInfo.outputState.depthStencilFormat = GetSwapchain()->GetDepthFormat(); - gpCreateInfo.pPipelineInterface = mQuadsPipelineInterfaces[i]; - PPX_CHECKED_CALL(GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &mQuadsPipelines[i])); + // Pre-load the current pipeline variant. + GetFullscreenQuadPipeline(); +} + +void GraphicsBenchmarkApp::UpdateOffscreenBuffer(grfx::Format format, int w, int h) +{ + { + // Checking if we still have the same buffer format. + const auto& frame = mOffscreenFrame.back(); + if ((frame.colorFormat == format) && (frame.width == w) && (frame.height == h)) { + return; + } + } + GetDevice()->WaitIdle(); + for (auto& frame : mOffscreenFrame) { + DestroyOffscreenFrame(frame); + CreateOffscreenFrame(frame, format, GetSwapchain()->GetDepthFormat(), w, h); } } @@ -744,6 +862,22 @@ void GraphicsBenchmarkApp::ProcessKnobs() } ProcessQuadsKnobs(); + + bool offscreenChanged = pRenderOffscreen->DigestUpdate(); + if (offscreenChanged) { + pBlitOffscreen->SetVisible(pRenderOffscreen->GetValue()); + pFramebufferFormat->SetVisible(pRenderOffscreen->GetValue()); + pResolution->SetVisible(pRenderOffscreen->GetValue()); + } + bool framebufferChanged = pResolution->DigestUpdate() || pFramebufferFormat->DigestUpdate(); + + if ((offscreenChanged && pRenderOffscreen->GetValue()) || framebufferChanged) { + std::pair resolution = mResolutionOptions[pResolution->GetIndex()]; + + int fbWidth = (resolution.first > 0 ? resolution.first : GetSwapchain()->GetWidth()); + int fbHeight = (resolution.second > 0 ? resolution.second : GetSwapchain()->GetHeight()); + UpdateOffscreenBuffer(RenderFormat(), fbWidth, fbHeight); + } } void GraphicsBenchmarkApp::ProcessQuadsKnobs() @@ -862,7 +996,22 @@ void GraphicsBenchmarkApp::Render() } #endif - RecordCommandBuffer(frame, swapchain, imageIndex); + RenderPasses swapchainRenderPasses = SwapchainRenderPasses(swapchain, imageIndex); + RenderPasses renderPasses = swapchainRenderPasses; + if (pRenderOffscreen->GetValue()) { + renderPasses = OffscreenRenderPasses(mOffscreenFrame[0]); + if (pBlitOffscreen->GetValue()) { + renderPasses.uiRenderPass = swapchainRenderPasses.uiRenderPass; + renderPasses.uiClearRenderPass = swapchainRenderPasses.uiClearRenderPass; + renderPasses.blitRenderPass = swapchainRenderPasses.noloadRenderPass; + } + else { + renderPasses.uiRenderPass = swapchainRenderPasses.uiClearRenderPass; + renderPasses.uiClearRenderPass = swapchainRenderPasses.uiClearRenderPass; + } + } + + RecordCommandBuffer(frame, renderPasses, imageIndex); grfx::SubmitInfo submitInfo = {}; submitInfo.commandBufferCount = 1; @@ -951,16 +1100,29 @@ void GraphicsBenchmarkApp::DrawExtraInfo() ImGui::Text("%.2f fps ", gpuFPS); ImGui::NextColumn(); - const uint32_t width = GetSwapchain()->GetWidth(); - const uint32_t height = GetSwapchain()->GetHeight(); + const grfx::Format swapchainColorFormat = GetSwapchain()->GetColorFormat(); + const uint32_t swapchainWidth = GetSwapchain()->GetWidth(); + const uint32_t swapchainHeight = GetSwapchain()->GetHeight(); ImGui::Text("Swapchain resolution"); ImGui::NextColumn(); - ImGui::Text("%d x %d", width, height); + ImGui::Text("%d x %d", swapchainWidth, swapchainHeight); ImGui::NextColumn(); + bool isOffscreen = pRenderOffscreen->GetValue(); + const grfx::Format colorFormat = isOffscreen ? mOffscreenFrame.back().colorFormat : swapchainColorFormat; + const uint32_t width = isOffscreen ? mOffscreenFrame.back().width : swapchainWidth; + const uint32_t height = isOffscreen ? mOffscreenFrame.back().height : swapchainHeight; + if (isOffscreen) { + ImGui::Text("Framebuffer"); + ImGui::NextColumn(); + ImGui::Text("%d x %d (%s)", width, height, ToString(colorFormat)); + ImGui::NextColumn(); + } + const uint32_t quad_count = pFullscreenQuadsCount->GetValue(); if (quad_count) { - const float dataWriteInGb = (static_cast(width) * static_cast(height) * 4.f * quad_count) / (1024.f * 1024.f * 1024.f); + const auto texelSize = static_cast(grfx::GetFormatDescription(colorFormat)->bytesPerTexel); + const float dataWriteInGb = (static_cast(width) * static_cast(height) * texelSize * quad_count) / (1024.f * 1024.f * 1024.f); ImGui::Text("Write Data"); ImGui::NextColumn(); ImGui::Text("%.2f GB", dataWriteInGb); @@ -975,25 +1137,233 @@ void GraphicsBenchmarkApp::DrawExtraInfo() ImGui::Columns(1); } -void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainPtr swapchain, uint32_t imageIndex) +GraphicsBenchmarkApp::RenderPasses GraphicsBenchmarkApp::SwapchainRenderPasses(grfx::SwapchainPtr swapchain, uint32_t imageIndex) +{ + return RenderPasses{ + swapchain->GetRenderPass(imageIndex, ppx::grfx::AttachmentLoadOp::ATTACHMENT_LOAD_OP_LOAD), + swapchain->GetRenderPass(imageIndex, ppx::grfx::AttachmentLoadOp::ATTACHMENT_LOAD_OP_CLEAR), + swapchain->GetRenderPass(imageIndex, ppx::grfx::AttachmentLoadOp::ATTACHMENT_LOAD_OP_DONT_CARE), + swapchain->GetRenderPass(imageIndex, ppx::grfx::AttachmentLoadOp::ATTACHMENT_LOAD_OP_LOAD), + swapchain->GetRenderPass(imageIndex, ppx::grfx::AttachmentLoadOp::ATTACHMENT_LOAD_OP_CLEAR), + }; +} + +ppx::Result GraphicsBenchmarkApp::CreateBlitContext(BlitContext& blit) +{ + // Descriptor set layout + { + // Descriptor set layout + grfx::DescriptorSetLayoutCreateInfo layoutCreateInfo = {}; + layoutCreateInfo.bindings.push_back(grfx::DescriptorBinding(0, grfx::DESCRIPTOR_TYPE_SAMPLED_IMAGE)); + layoutCreateInfo.bindings.push_back(grfx::DescriptorBinding(1, grfx::DESCRIPTOR_TYPE_SAMPLER)); + + PPX_CHECKED_CALL(GetDevice()->CreateDescriptorSetLayout(&layoutCreateInfo, &blit.descriptorSetLayout)); + } + + // Pipeline + { + SetupShader("basic/shaders", "FullScreenTriangle.vs", &blit.vs); + SetupShader("basic/shaders", "FullScreenTriangle.ps", &blit.ps); + + grfx::FullscreenQuadCreateInfo createInfo = {}; + createInfo.VS = blit.vs; + createInfo.PS = blit.ps; + createInfo.setCount = 1; + createInfo.sets[0].set = 0; + createInfo.sets[0].pLayout = blit.descriptorSetLayout; + createInfo.renderTargetCount = 1; + createInfo.renderTargetFormats[0] = GetSwapchain()->GetColorFormat(); + createInfo.depthStencilFormat = GetSwapchain()->GetDepthFormat(); + + PPX_CHECKED_CALL(GetDevice()->CreateFullscreenQuad(&createInfo, &blit.quad)); + } + + return ppx::SUCCESS; +} + +GraphicsBenchmarkApp::RenderPasses GraphicsBenchmarkApp::OffscreenRenderPasses(const OffscreenFrame& frame) +{ + return RenderPasses{ + frame.loadRenderPass, + frame.clearRenderPass, + frame.noloadRenderPass, + nullptr, + nullptr, + nullptr, + &frame, + }; +} + +void GraphicsBenchmarkApp::DestroyOffscreenFrame(OffscreenFrame& frame) +{ + GetDevice()->DestroyRenderPass(frame.loadRenderPass); + GetDevice()->DestroyRenderPass(frame.clearRenderPass); + GetDevice()->DestroyRenderPass(frame.noloadRenderPass); + + for (auto& rtv : frame.renderTargetViews) { + GetDevice()->DestroyRenderTargetView(rtv); + } + GetDevice()->DestroyDepthStencilView(frame.depthStencilView); + + GetDevice()->FreeDescriptorSet(frame.blitDescriptorSet); + GetDevice()->DestroyTexture(frame.blitSource); + + GetDevice()->DestroyImage(frame.colorImage); + GetDevice()->DestroyImage(frame.depthImage); + + // Reset all the pointers to nullptr. + frame = {}; +} + +ppx::Result GraphicsBenchmarkApp::CreateOffscreenFrame(OffscreenFrame& frame, grfx::Format colorFormat, grfx::Format depthFormat, uint32_t width, uint32_t height) +{ + frame = OffscreenFrame{width, height, colorFormat, depthFormat}; + { + grfx::ImageCreateInfo colorCreateInfo = grfx::ImageCreateInfo::RenderTarget2D(width, height, colorFormat); + colorCreateInfo.initialState = grfx::RESOURCE_STATE_PRESENT; + colorCreateInfo.usageFlags.bits.sampled = true; + ppx::Result ppxres = GetDevice()->CreateImage(&colorCreateInfo, &frame.colorImage); + if (ppxres != ppx::SUCCESS) { + return ppxres; + } + } + + if (depthFormat != grfx::Format::FORMAT_UNDEFINED) { + grfx::ImageCreateInfo depthCreateInfo = grfx::ImageCreateInfo::DepthStencilTarget(width, height, depthFormat); + ppx::Result ppxres = GetDevice()->CreateImage(&depthCreateInfo, &frame.depthImage); + if (ppxres != ppx::SUCCESS) { + return ppxres; + } + } + + if (frame.depthImage) { + grfx::DepthStencilViewCreateInfo dsvCreateInfo = {}; + dsvCreateInfo = + grfx::DepthStencilViewCreateInfo::GuessFromImage(frame.depthImage); + dsvCreateInfo.depthLoadOp = ppx::grfx::ATTACHMENT_LOAD_OP_CLEAR; + dsvCreateInfo.stencilLoadOp = ppx::grfx::ATTACHMENT_LOAD_OP_CLEAR; + dsvCreateInfo.ownership = ppx::grfx::OWNERSHIP_RESTRICTED; + + Result ppxres = GetDevice()->CreateDepthStencilView(&dsvCreateInfo, &frame.depthStencilView); + if (ppxres != ppx::SUCCESS) { + return ppxres; + } + } + + struct + { + grfx::RenderPassPtr& ptr; + grfx::AttachmentLoadOp op; + grfx::RenderTargetViewPtr& rtv; + } renderpasses[] = { + {frame.loadRenderPass, grfx::ATTACHMENT_LOAD_OP_LOAD, frame.renderTargetViews[0]}, + {frame.clearRenderPass, grfx::ATTACHMENT_LOAD_OP_CLEAR, frame.renderTargetViews[1]}, + {frame.noloadRenderPass, grfx::ATTACHMENT_LOAD_OP_DONT_CARE, frame.renderTargetViews[2]}, + }; + + for (auto& renderpass : renderpasses) { + grfx::RenderTargetViewCreateInfo rtvCreateInfo = + grfx::RenderTargetViewCreateInfo::GuessFromImage(frame.colorImage); + rtvCreateInfo.loadOp = renderpass.op; + rtvCreateInfo.ownership = grfx::OWNERSHIP_RESTRICTED; + Result ppxres = GetDevice()->CreateRenderTargetView(&rtvCreateInfo, &renderpass.rtv); + + grfx::RenderPassCreateInfo rpCreateInfo = {}; + rpCreateInfo.width = width; + rpCreateInfo.height = height; + rpCreateInfo.renderTargetCount = 1; + rpCreateInfo.pRenderTargetViews[0] = renderpass.rtv; + rpCreateInfo.pDepthStencilView = frame.depthStencilView; + rpCreateInfo.renderTargetClearValues[0] = {{0.0f, 0.0f, 0.0f, 0.0f}}; + rpCreateInfo.depthStencilClearValue = {1.0f, 0xFF}; + rpCreateInfo.ownership = grfx::OWNERSHIP_RESTRICTED; + + GetDevice()->CreateRenderPass(&rpCreateInfo, &renderpass.ptr); + } + + { + grfx::TextureCreateInfo createInfo = {}; + createInfo.pImage = frame.colorImage; + createInfo.imageType = grfx::IMAGE_TYPE_2D; + createInfo.width = width; + createInfo.height = height; + createInfo.depth = 1; + createInfo.imageFormat = colorFormat; + createInfo.sampleCount = grfx::SAMPLE_COUNT_1; + createInfo.mipLevelCount = 1; + createInfo.arrayLayerCount = 1; + createInfo.usageFlags.bits.inputAttachment = true; + createInfo.usageFlags.bits.sampled = true; + createInfo.usageFlags.bits.colorAttachment = true; + createInfo.usageFlags.bits.storage = true; + createInfo.memoryUsage = grfx::MEMORY_USAGE_GPU_ONLY; + createInfo.initialState = grfx::RESOURCE_STATE_SHADER_RESOURCE; + + PPX_CHECKED_CALL(GetDevice()->CreateTexture(&createInfo, &frame.blitSource)); + } + + // Allocate descriptor set + PPX_CHECKED_CALL(GetDevice()->AllocateDescriptorSet(mDescriptorPool, mBlit.descriptorSetLayout, &frame.blitDescriptorSet)); + + // Write descriptors + { + grfx::WriteDescriptor writes[2] = {}; + writes[0].binding = 0; + writes[0].arrayIndex = 0; + writes[0].type = grfx::DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writes[0].pImageView = frame.blitSource->GetSampledImageView(); + + writes[1].binding = 1; + writes[1].type = grfx::DESCRIPTOR_TYPE_SAMPLER; + writes[1].pSampler = mLinearSampler; + + PPX_CHECKED_CALL(frame.blitDescriptorSet->UpdateDescriptors(2, writes)); + } + + return ppx::SUCCESS; +} + +ppx::grfx::Format GraphicsBenchmarkApp::RenderFormat() +{ + grfx::Format renderFormat = kFramebufferFormatTypes[pFramebufferFormat->GetIndex()]; + if (!pRenderOffscreen->GetValue() || renderFormat == grfx::Format::FORMAT_UNDEFINED) { + return GetSwapchain()->GetColorFormat(); + } + return renderFormat; +} + +void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, const RenderPasses& renderpasses, uint32_t imageIndex) { PPX_CHECKED_CALL(frame.cmd->Begin()); // Write start timestamp frame.cmd->WriteTimestamp(frame.timestampQuery, grfx::PIPELINE_STAGE_TOP_OF_PIPE_BIT, /* queryIndex = */ 0); + if (!pRenderOffscreen->GetValue()) { + frame.cmd->SetScissors(GetScissor()); + frame.cmd->SetViewports(GetViewport()); + } + else { + uint32_t width = mOffscreenFrame.back().width; + uint32_t height = mOffscreenFrame.back().height; + frame.cmd->SetScissors({0, 0, width, height}); + frame.cmd->SetViewports({0, 0, static_cast(width), static_cast(height), 0.0, 1.0}); + } - frame.cmd->SetScissors(GetScissor()); - frame.cmd->SetViewports(GetViewport()); - - grfx::RenderPassPtr currentRenderPass = swapchain->GetRenderPass(imageIndex, grfx::ATTACHMENT_LOAD_OP_CLEAR); + grfx::RenderPassPtr currentRenderPass = renderpasses.clearRenderPass; PPX_ASSERT_MSG(!currentRenderPass.IsNull(), "render pass object is null"); -#if defined(PPX_BUILD_XR) - if (!IsXrEnabled()) -#endif - { + const grfx::ImagePtr framebufferImage = currentRenderPass->GetRenderTargetImage(0); + const grfx::ImagePtr swapchainImage = (renderpasses.offscreen ? renderpasses.uiRenderPass->GetRenderTargetImage(0) : framebufferImage); + + const grfx::ResourceState presentState = IsXrEnabled() ? grfx::RESOURCE_STATE_RENDER_TARGET : grfx::RESOURCE_STATE_PRESENT; + grfx::ResourceState resourceStates[2] = {presentState, presentState}; + grfx::ResourceState* swapchainState = &resourceStates[0]; + grfx::ResourceState* framebufferState = (renderpasses.offscreen ? &resourceStates[1] : &resourceStates[0]); + + if (*framebufferState != grfx::RESOURCE_STATE_RENDER_TARGET) { // Transition image layout PRESENT->RENDER before the first renderpass - frame.cmd->TransitionImageLayout(currentRenderPass->GetRenderTargetImage(0), PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_PRESENT, grfx::RESOURCE_STATE_RENDER_TARGET); + frame.cmd->TransitionImageLayout(framebufferImage, PPX_ALL_SUBRESOURCES, *framebufferState, grfx::RESOURCE_STATE_RENDER_TARGET); + *framebufferState = grfx::RESOURCE_STATE_RENDER_TARGET; } bool renderScene = pEnableSkyBox->GetValue() || pEnableSpheres->GetValue(); @@ -1013,8 +1383,8 @@ void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainP uint32_t quadsCount = pFullscreenQuadsCount->GetValue(); bool singleRenderpass = pFullscreenQuadsSingleRenderpass->GetValue(); if (quadsCount > 0) { - currentRenderPass = swapchain->GetRenderPass(imageIndex, grfx::ATTACHMENT_LOAD_OP_DONT_CARE); - frame.cmd->BindGraphicsPipeline(mQuadsPipelines[pFullscreenQuadsType->GetIndex()]); + currentRenderPass = renderpasses.noloadRenderPass; + frame.cmd->BindGraphicsPipeline(GetFullscreenQuadPipeline()); frame.cmd->BindVertexBuffers(1, &mFullscreenQuads.vertexBuffer, &mFullscreenQuads.vertexBinding.GetStride()); if (pFullscreenQuadsType->GetIndex() == static_cast(FullscreenQuadsType::FULLSCREEN_QUADS_TYPE_TEXTURE)) { @@ -1028,8 +1398,8 @@ void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainP if (!singleRenderpass) { // If quads are using multiple renderpasses, transition image layout in between to force resolve frame.cmd->EndRenderPass(); - frame.cmd->TransitionImageLayout(currentRenderPass->GetRenderTargetImage(0), PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_RENDER_TARGET, grfx::RESOURCE_STATE_SHADER_RESOURCE); - frame.cmd->TransitionImageLayout(currentRenderPass->GetRenderTargetImage(0), PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_SHADER_RESOURCE, grfx::RESOURCE_STATE_RENDER_TARGET); + frame.cmd->TransitionImageLayout(framebufferImage, PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_RENDER_TARGET, grfx::RESOURCE_STATE_SHADER_RESOURCE); + frame.cmd->TransitionImageLayout(framebufferImage, PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_SHADER_RESOURCE, grfx::RESOURCE_STATE_RENDER_TARGET); if (i == (quadsCount - 1)) { // For the last quad, do not begin another renderpass break; @@ -1043,15 +1413,43 @@ void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainP } // Write end timestamp + // Note the framebuffer is still in RENDER_TARGET state, although it should not really be a problem. frame.cmd->WriteTimestamp(frame.timestampQuery, grfx::PIPELINE_STAGE_TOP_OF_PIPE_BIT, /* queryIndex = */ 1); + if (renderpasses.blitRenderPass) { + currentRenderPass = renderpasses.blitRenderPass; + PPX_ASSERT_MSG(!currentRenderPass.IsNull(), "render pass object is null"); + + if (*framebufferState != grfx::RESOURCE_STATE_SHADER_RESOURCE) { + frame.cmd->TransitionImageLayout(framebufferImage, PPX_ALL_SUBRESOURCES, *framebufferState, grfx::RESOURCE_STATE_SHADER_RESOURCE); + *framebufferState = grfx::RESOURCE_STATE_SHADER_RESOURCE; + } + if (*swapchainState != grfx::RESOURCE_STATE_RENDER_TARGET) { + frame.cmd->TransitionImageLayout(swapchainImage, PPX_ALL_SUBRESOURCES, *swapchainState, grfx::RESOURCE_STATE_RENDER_TARGET); + *swapchainState = grfx::RESOURCE_STATE_RENDER_TARGET; + } + + frame.cmd->SetScissors(GetScissor()); + frame.cmd->SetViewports(GetViewport()); + + frame.cmd->BeginRenderPass(currentRenderPass); + const grfx::DescriptorSet* descriptorSet = renderpasses.offscreen->blitDescriptorSet.Get(); + frame.cmd->Draw(mBlit.quad, 1, &descriptorSet); + frame.cmd->EndRenderPass(); + } + // Record commands for the GUI using one last renderpass if ( #if defined(PPX_BUILD_XR) !IsXrEnabled() && #endif GetSettings()->enableImGui) { - currentRenderPass = swapchain->GetRenderPass(imageIndex, (renderScene || quadsCount > 0) ? grfx::ATTACHMENT_LOAD_OP_LOAD : grfx::ATTACHMENT_LOAD_OP_CLEAR); + + if (*swapchainState != grfx::RESOURCE_STATE_RENDER_TARGET) { + frame.cmd->TransitionImageLayout(swapchainImage, PPX_ALL_SUBRESOURCES, *swapchainState, grfx::RESOURCE_STATE_RENDER_TARGET); + *swapchainState = grfx::RESOURCE_STATE_RENDER_TARGET; + } + currentRenderPass = (renderScene || quadsCount > 0) ? renderpasses.uiRenderPass : renderpasses.uiClearRenderPass; PPX_ASSERT_MSG(!currentRenderPass.IsNull(), "render pass object is null"); frame.cmd->BeginRenderPass(currentRenderPass); UpdateGUI(); @@ -1059,12 +1457,14 @@ void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainP frame.cmd->EndRenderPass(); } -#if defined(PPX_BUILD_XR) - if (!IsXrEnabled()) -#endif - { - // Transition image layout RENDER->PRESENT after the last renderpass - frame.cmd->TransitionImageLayout(currentRenderPass->GetRenderTargetImage(0), PPX_ALL_SUBRESOURCES, grfx::RESOURCE_STATE_RENDER_TARGET, grfx::RESOURCE_STATE_PRESENT); + if (*framebufferState != presentState) { + frame.cmd->TransitionImageLayout(framebufferImage, PPX_ALL_SUBRESOURCES, *framebufferState, presentState); + *framebufferState = presentState; + } + + if (*swapchainState != presentState) { + frame.cmd->TransitionImageLayout(swapchainImage, PPX_ALL_SUBRESOURCES, *swapchainState, presentState); + *swapchainState = presentState; } // Resolve queries @@ -1076,7 +1476,7 @@ void GraphicsBenchmarkApp::RecordCommandBuffer(PerFrame& frame, grfx::SwapchainP void GraphicsBenchmarkApp::RecordCommandBufferSkyBox(PerFrame& frame) { // Bind resources - frame.cmd->BindGraphicsPipeline(mSkyBox.pipeline); + frame.cmd->BindGraphicsPipeline(GetSkyBoxPipeline()); frame.cmd->BindIndexBuffer(mSkyBox.mesh); frame.cmd->BindVertexBuffers(mSkyBox.mesh); @@ -1160,7 +1560,12 @@ void GraphicsBenchmarkApp::RecordCommandBufferFullscreenQuad(PerFrame& frame, si void GraphicsBenchmarkApp::SetupShader(const std::filesystem::path& fileName, grfx::ShaderModule** ppShaderModule) { - std::vector bytecode = LoadShader(kShaderBaseDir, fileName); + SetupShader(kShaderBaseDir, fileName, ppShaderModule); +} + +void GraphicsBenchmarkApp::SetupShader(const char* baseDir, const std::filesystem::path& fileName, grfx::ShaderModule** ppShaderModule) +{ + std::vector bytecode = LoadShader(baseDir, fileName); PPX_ASSERT_MSG(!bytecode.empty(), "shader bytecode load failed for " << kShaderBaseDir << " " << fileName); grfx::ShaderModuleCreateInfo shaderCreateInfo = {static_cast(bytecode.size()), bytecode.data()}; PPX_CHECKED_CALL(GetDevice()->CreateShaderModule(&shaderCreateInfo, ppShaderModule)); diff --git a/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.h b/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.h index 56f798b2f..192da4346 100644 --- a/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.h +++ b/benchmarks/graphics_pipeline/GraphicsBenchmarkApp.h @@ -19,6 +19,7 @@ #include "MultiDimensionalIndexer.h" #include "ppx/grfx/grfx_config.h" +#include "ppx/grfx/grfx_format.h" #include "ppx/knob.h" #include "ppx/math_config.h" #include "ppx/ppx.h" @@ -90,6 +91,78 @@ static constexpr std::array kFullscreenQuadsColorsValues = { float3(0.0f, 1.0f, 0.0f), float3(1.0f, 1.0f, 1.0f)}; +static constexpr std::array kFramebufferFormatTypes = { + // Some format may not be supported on all devices. + // We may want to filter based on device capability. + grfx::Format::FORMAT_UNDEFINED, // Use Swapchain format + grfx::Format::FORMAT_R8G8B8A8_UNORM, + grfx::Format::FORMAT_B8G8R8A8_UNORM, + grfx::Format::FORMAT_R8G8B8A8_SRGB, + grfx::Format::FORMAT_B8G8R8A8_SRGB, + grfx::Format::FORMAT_R16G16B16A16_UNORM, + grfx::Format::FORMAT_R16G16B16A16_FLOAT, + grfx::Format::FORMAT_R32G32B32A32_FLOAT, + grfx::Format::FORMAT_R10G10B10A2_UNORM, + grfx::Format::FORMAT_R11G11B10_FLOAT, + grfx::Format::FORMAT_R8_UNORM, + grfx::Format::FORMAT_R16_UNORM, + grfx::Format::FORMAT_R8G8_UNORM, + grfx::Format::FORMAT_R16G16_UNORM, +}; + +static constexpr std::array, 1 + 8> kSimpleResolutions = {{ + // 1x1 + {1, 1}, + // 2^n square + {64, 64}, + {128, 128}, + {256, 256}, + {512, 512}, + {1024, 1024}, + {2048, 2048}, + {4096, 4096}, + {8192, 8192}, +}}; + +static constexpr std::array, 6 + 5 + 2> kCommonResolutions = {{ + // 16:9 Wide screen + {1280, 720}, // 720p + {1920, 1080}, // 1080p + {2560, 1440}, // 1440p + {3840, 2160}, // 4K + {5120, 2880}, // 5K + {7680, 4320}, // 8K + // VGA + {320, 240}, // QVGA + {480, 320}, // HVGA + {640, 480}, // VGA + {800, 600}, // SVGA + {1024, 768}, // XGA + // Other common display resolution + {3840, 1600}, // 4K ultrawide + {5120, 2160}, // 5K ultrawide +}}; + +static constexpr std::array, 8 + 9> kVRPerEyeResolutions = {{ + {720, 720}, + {960, 960}, + {1440, 1440}, + {1920, 1920}, + {2880, 2880}, + {3840, 3840}, + {5760, 5760}, + {7680, 7680}, + {1800, 1920}, // Quest Pro + {1832, 1920}, // Quest 2 + {2064, 2208}, // Quest 3 + {1440, 1600}, // Valve Index + {1080, 1200}, // HTC Vive + {2448, 2448}, // HTC Vive Pro 2 + {960, 1080}, // PlayStation VR + {2000, 2040}, // PlayStation VR 2 + {3680, 3140}, // Vision Pro, estimation from Wikipedia +}}; + class GraphicsBenchmarkApp : public ppx::Application { @@ -146,7 +219,6 @@ class GraphicsBenchmarkApp grfx::BufferPtr uniformBuffer; grfx::DescriptorSetLayoutPtr descriptorSetLayout; grfx::PipelineInterfacePtr pipelineInterface; - grfx::GraphicsPipelinePtr pipeline; std::vector descriptorSets; }; @@ -165,14 +237,52 @@ class GraphicsBenchmarkApp std::string name; }; + struct SkyBoxPipelineKey + { + grfx::Format renderFormat; + + bool operator==(const SkyBoxPipelineKey& rhs) const + { + return renderFormat == rhs.renderFormat; + } + + struct Hash + { + size_t operator()(const SkyBoxPipelineKey& key) const + { + return static_cast(key.renderFormat); + } + }; + }; + + struct QuadPipelineKey + { + grfx::Format renderFormat; + FullscreenQuadsType quadType; + + bool operator==(const QuadPipelineKey& rhs) const + { + return renderFormat == rhs.renderFormat && quadType == rhs.quadType; + } + + struct Hash + { + size_t operator()(const QuadPipelineKey& key) const + { + return (static_cast(key.renderFormat) * kFullscreenQuadsTypes.size()) | static_cast(key.quadType); + } + }; + }; + struct SpherePipelineKey { - uint8_t ps; - uint8_t vs; - uint8_t vertexFormat; - uint8_t vertexAttributeLayout; - bool enableDepth; - bool enableAlphaBlend; + uint8_t ps; + uint8_t vs; + uint8_t vertexFormat; + uint8_t vertexAttributeLayout; + bool enableDepth; + bool enableAlphaBlend; + grfx::Format renderFormat; static_assert(kAvailablePsShaders.size() < (1 << (8 * sizeof(ps)))); static_assert(kAvailableVsShaders.size() < (1 << (8 * sizeof(vs)))); @@ -186,7 +296,8 @@ class GraphicsBenchmarkApp vertexFormat == rhs.vertexFormat && vertexAttributeLayout == rhs.vertexAttributeLayout && enableDepth == rhs.enableDepth && - enableAlphaBlend == rhs.enableAlphaBlend; + enableAlphaBlend == rhs.enableAlphaBlend && + renderFormat == rhs.renderFormat; } struct Hash @@ -194,7 +305,7 @@ class GraphicsBenchmarkApp // Not a good hash function, but good enough. size_t operator()(const SpherePipelineKey& key) const { - size_t res = 0; + size_t res = static_cast(key.renderFormat); res = (res * kAvailablePsShaders.size()) | key.ps; res = (res * kAvailableVsShaders.size()) | key.vs; @@ -207,8 +318,53 @@ class GraphicsBenchmarkApp }; }; + struct OffscreenFrame + { + uint32_t width; + uint32_t height; + + grfx::Format colorFormat; + grfx::Format depthFormat; + + grfx::RenderPassPtr loadRenderPass; + grfx::RenderPassPtr clearRenderPass; + grfx::RenderPassPtr noloadRenderPass; + + grfx::RenderTargetViewPtr renderTargetViews[3]; + grfx::DepthStencilViewPtr depthStencilView; + // The actual image + grfx::ImagePtr depthImage; + grfx::ImagePtr colorImage; + + grfx::TexturePtr blitSource; + grfx::DescriptorSetPtr blitDescriptorSet; + }; + + struct RenderPasses + { + grfx::RenderPassPtr loadRenderPass; + grfx::RenderPassPtr clearRenderPass; + grfx::RenderPassPtr noloadRenderPass; + grfx::RenderPassPtr uiRenderPass; + grfx::RenderPassPtr uiClearRenderPass; + grfx::RenderPassPtr blitRenderPass; + const OffscreenFrame* offscreen = nullptr; + }; + + struct BlitContext + { + grfx::ShaderModulePtr vs; + grfx::ShaderModulePtr ps; + + // Note: the blit implementated here does not perserve aspect ratio. + grfx::DescriptorSetLayoutPtr descriptorSetLayout; + grfx::FullscreenQuadPtr quad; + }; + private: using SpherePipelineMap = std::unordered_map; + using SkyboxPipelineMap = std::unordered_map; + using QuadPipelineMap = std::unordered_map; std::vector mPerFrame; FreeCamera mCamera; @@ -218,12 +374,14 @@ class GraphicsBenchmarkApp uint64_t mGpuWorkDuration; grfx::SamplerPtr mLinearSampler; grfx::DescriptorPoolPtr mDescriptorPool; + std::vector mOffscreenFrame; // SkyBox resources Entity mSkyBox; grfx::ShaderModulePtr mVSSkyBox; grfx::ShaderModulePtr mPSSkyBox; grfx::TexturePtr mSkyBoxTexture; + SkyboxPipelineMap mSkyBoxPipelines; // Spheres resources Entity mSphere; @@ -242,10 +400,12 @@ class GraphicsBenchmarkApp Entity2D mFullscreenQuads; grfx::ShaderModulePtr mVSQuads; grfx::TexturePtr mQuadsTexture; - std::array mQuadsPipelines; + QuadPipelineMap mQuadsPipelines; std::array mQuadsPipelineInterfaces; std::array mQuadsPs; + BlitContext mBlit; + private: std::shared_ptr> pKnobVs; std::shared_ptr> pKnobPs; @@ -264,6 +424,12 @@ class GraphicsBenchmarkApp std::shared_ptr pEnableSpheres; std::shared_ptr pAllTexturesTo1x1; + std::shared_ptr pRenderOffscreen; + std::shared_ptr pBlitOffscreen; + std::shared_ptr> pFramebufferFormat; + std::shared_ptr> pResolution; + std::vector> mResolutionOptions; + private: // ===================================================================== // SETUP (One-time setup for objects) @@ -290,7 +456,9 @@ class GraphicsBenchmarkApp void SetupSpheresPipelines(); void SetupFullscreenQuadsPipelines(); - Result CompileSpherePipeline(const SpherePipelineKey& key); + Result CompilePipeline(const SkyBoxPipelineKey& key); + Result CompilePipeline(const SpherePipelineKey& key); + Result CompilePipeline(const QuadPipelineKey& key); // Update descriptors // Note: Descriptors can be updated within rendering loop @@ -298,6 +466,8 @@ class GraphicsBenchmarkApp void UpdateSphereDescriptors(); void UpdateFullscreenQuadsDescriptors(); + void UpdateOffscreenBuffer(grfx::Format format, int w, int h); + // ===================================================================== // RENDERING LOOP (Called every frame) // ===================================================================== @@ -312,7 +482,7 @@ class GraphicsBenchmarkApp void DrawExtraInfo(); // Record this frame's command buffer with multiple renderpasses - void RecordCommandBuffer(PerFrame& frame, grfx::SwapchainPtr swapchain, uint32_t imageIndex); + void RecordCommandBuffer(PerFrame& frame, const RenderPasses& renderPasses, uint32_t imageIndex); // Records commands to render * in this frame's command buffer, with the current renderpass void RecordCommandBufferSkyBox(PerFrame& frame); @@ -330,9 +500,19 @@ class GraphicsBenchmarkApp // Loads shader at shaderBaseDir/fileName and creates it at ppShaderModule void SetupShader(const std::filesystem::path& fileName, grfx::ShaderModule** ppShaderModule); + void SetupShader(const char* baseDir, const std::filesystem::path& fileName, grfx::ShaderModule** ppShaderModule); // Compile or load from cache currently required pipeline. grfx::GraphicsPipelinePtr GetSpherePipeline(); + grfx::GraphicsPipelinePtr GetFullscreenQuadPipeline(); + grfx::GraphicsPipelinePtr GetSkyBoxPipeline(); + + Result CreateOffscreenFrame(OffscreenFrame&, grfx::Format colorFormat, grfx::Format depthFormat, uint32_t width, uint32_t height); + void DestroyOffscreenFrame(OffscreenFrame&); + Result CreateBlitContext(BlitContext& blit); + RenderPasses SwapchainRenderPasses(grfx::SwapchainPtr swapchain, uint32_t imageIndex); + RenderPasses OffscreenRenderPasses(const OffscreenFrame&); + grfx::Format RenderFormat(); }; #endif // BENCHMARKS_GRAPHICS_PIPELINE_GRAPHICS_BENCHMARK_APP_H diff --git a/benchmarks/graphics_pipeline/build.gradle b/benchmarks/graphics_pipeline/build.gradle index 3f8f13e67..9effe58ae 100644 --- a/benchmarks/graphics_pipeline/build.gradle +++ b/benchmarks/graphics_pipeline/build.gradle @@ -1,4 +1,5 @@ ArrayList projectAssets = [ + "basic/shaders/spv", "benchmarks/shaders/spv", "benchmarks/textures", "basic/models", diff --git a/include/ppx/grfx/grfx_format.h b/include/ppx/grfx/grfx_format.h index b40eed90b..7d44a2c8e 100644 --- a/include/ppx/grfx/grfx_format.h +++ b/include/ppx/grfx/grfx_format.h @@ -219,6 +219,9 @@ struct FormatComponentOffset struct FormatDesc { + // BigWheels specific format name. + const char* name; + // The texel data type, e.g. UNORM, SNORM, UINT, etc. FormatDataType dataType; @@ -241,7 +244,7 @@ struct FormatDesc // and will be set to -1. int8_t bytesPerComponent; - //The layout of the format (linear, packed, or compressed). + // The layout of the format (linear, packed, or compressed). FormatLayout layout; // The components (channels) represented by the format, @@ -257,6 +260,8 @@ struct FormatDesc //! @brief Gets a description of the given /b format. const FormatDesc* GetFormatDescription(grfx::Format format); +const char* ToString(grfx::Format format); + } // namespace grfx } // namespace ppx diff --git a/src/ppx/grfx/grfx_format.cpp b/src/ppx/grfx/grfx_format.cpp index 184a26c95..26f04c5d7 100644 --- a/src/ppx/grfx/grfx_format.cpp +++ b/src/ppx/grfx/grfx_format.cpp @@ -18,28 +18,30 @@ namespace ppx { namespace grfx { -#define UNCOMPRESSED_FORMAT(Type, Aspect, BytesPerTexel, BytesPerComponent, Layout, Component, ComponentOffsets) \ - { \ - FORMAT_DATA_TYPE_##Type, \ - FORMAT_ASPECT_##Aspect, \ - BytesPerTexel, \ - /* blockWidth= */ 1, \ - BytesPerComponent, \ - FORMAT_LAYOUT_##Layout, \ - FORMAT_COMPONENT_##Component, \ - OFFSETS_##ComponentOffsets \ +#define UNCOMPRESSED_FORMAT(Name, Type, Aspect, BytesPerTexel, BytesPerComponent, Layout, Component, ComponentOffsets) \ + { \ + "" #Name, \ + FORMAT_DATA_TYPE_##Type, \ + FORMAT_ASPECT_##Aspect, \ + BytesPerTexel, \ + /* blockWidth= */ 1, \ + BytesPerComponent, \ + FORMAT_LAYOUT_##Layout, \ + FORMAT_COMPONENT_##Component, \ + OFFSETS_##ComponentOffsets \ } -#define COMPRESSED_FORMAT(Type, BytesPerBlock, BlockWidth, Component) \ - { \ - FORMAT_DATA_TYPE_##Type, \ - FORMAT_ASPECT_COLOR, \ - BytesPerBlock, \ - BlockWidth, \ - -1, \ - FORMAT_LAYOUT_COMPRESSED, \ - FORMAT_COMPONENT_##Component, \ - OFFSETS_UNDEFINED \ +#define COMPRESSED_FORMAT(Name, Type, BytesPerBlock, BlockWidth, Component) \ + { \ + "" #Name, \ + FORMAT_DATA_TYPE_##Type, \ + FORMAT_ASPECT_COLOR, \ + BytesPerBlock, \ + BlockWidth, \ + -1, \ + FORMAT_LAYOUT_COMPRESSED, \ + FORMAT_COMPONENT_##Component, \ + OFFSETS_UNDEFINED \ } // clang-format off @@ -56,120 +58,120 @@ namespace grfx { // constant time. constexpr FormatDesc formatDescs[] = { // clang-format off - // +----------------------------------------------------------------------------------------------------------------+ - // | ,-> bytes per texel | - // | | ,-> bytes per component | - // | grfx format | type | aspect | | Layout | Components | Offsets | - UNCOMPRESSED_FORMAT(/* UNDEFINED */ UNDEFINED, UNDEFINED, 0, 0, UNDEFINED, UNDEFINED, UNDEFINED), - UNCOMPRESSED_FORMAT(/* R8_SNORM */ SNORM, COLOR, 1, 1, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R8G8_SNORM */ SNORM, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), - UNCOMPRESSED_FORMAT(/* R8G8B8_SNORM */ SNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), - UNCOMPRESSED_FORMAT(/* R8G8B8A8_SNORM */ SNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), - UNCOMPRESSED_FORMAT(/* B8G8R8_SNORM */ SNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), - UNCOMPRESSED_FORMAT(/* B8G8R8A8_SNORM */ SNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), - - UNCOMPRESSED_FORMAT(/* R8_UNORM */ UNORM, COLOR, 1, 1, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R8G8_UNORM */ UNORM, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), - UNCOMPRESSED_FORMAT(/* R8G8B8_UNORM */ UNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), - UNCOMPRESSED_FORMAT(/* R8G8B8A8_UNORM */ UNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), - UNCOMPRESSED_FORMAT(/* B8G8R8_UNORM */ UNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), - UNCOMPRESSED_FORMAT(/* B8G8R8A8_UNORM */ UNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), - - UNCOMPRESSED_FORMAT(/* R8_SINT */ SINT, COLOR, 1, 1, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R8G8_SINT */ SINT, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), - UNCOMPRESSED_FORMAT(/* R8G8B8_SINT */ SINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), - UNCOMPRESSED_FORMAT(/* R8G8B8A8_SINT */ SINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), - UNCOMPRESSED_FORMAT(/* B8G8R8_SINT */ SINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), - UNCOMPRESSED_FORMAT(/* B8G8R8A8_SINT */ SINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), - - UNCOMPRESSED_FORMAT(/* R8_UINT */ UINT, COLOR, 1, 1, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R8G8_UINT */ UINT, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), - UNCOMPRESSED_FORMAT(/* R8G8B8_UINT */ UINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), - UNCOMPRESSED_FORMAT(/* R8G8B8A8_UINT */ UINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), - UNCOMPRESSED_FORMAT(/* B8G8R8_UINT */ UINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), - UNCOMPRESSED_FORMAT(/* B8G8R8A8_UINT */ UINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), - - UNCOMPRESSED_FORMAT(/* R16_SNORM */ SNORM, COLOR, 2, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R16G16_SNORM */ SNORM, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* R16G16B16_SNORM */ SNORM, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), - UNCOMPRESSED_FORMAT(/* R16G16B16A16_SNORM */ SNORM, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), - - UNCOMPRESSED_FORMAT(/* R16_UNORM */ UNORM, COLOR, 2, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R16G16_UNORM */ UNORM, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* R16G16B16_UNORM */ UNORM, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), - UNCOMPRESSED_FORMAT(/* R16G16B16A16_UNORM */ UNORM, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), - - UNCOMPRESSED_FORMAT(/* R16_SINT */ SINT, COLOR, 2, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R16G16_SINT */ SINT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* R16G16B16_SINT */ SINT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), - UNCOMPRESSED_FORMAT(/* R16G16B16A16_SINT */ SINT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), - - UNCOMPRESSED_FORMAT(/* R16_UINT */ UINT, COLOR, 2, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R16G16_UINT */ UINT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* R16G16B16_UINT */ UINT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), - UNCOMPRESSED_FORMAT(/* R16G16B16A16_UINT */ UINT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), - - UNCOMPRESSED_FORMAT(/* R16_FLOAT */ FLOAT, COLOR, 2, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R16G16_FLOAT */ FLOAT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* R16G16B16_FLOAT */ FLOAT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), - UNCOMPRESSED_FORMAT(/* R16G16B16A16_FLOAT */ FLOAT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), - - UNCOMPRESSED_FORMAT(/* R32_SINT */ SINT, COLOR, 4, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R32G32_SINT */ SINT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), - UNCOMPRESSED_FORMAT(/* R32G32B32_SINT */ SINT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), - UNCOMPRESSED_FORMAT(/* R32G32B32A32_SINT */ SINT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), - - UNCOMPRESSED_FORMAT(/* R32_UINT */ UINT, COLOR, 4, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R32G32_UINT */ UINT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), - UNCOMPRESSED_FORMAT(/* R32G32B32_UINT */ UINT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), - UNCOMPRESSED_FORMAT(/* R32G32B32A32_UINT */ UINT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), - - UNCOMPRESSED_FORMAT(/* R32_FLOAT */ FLOAT, COLOR, 4, 2, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R32G32_FLOAT */ FLOAT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), - UNCOMPRESSED_FORMAT(/* R32G32B32_FLOAT */ FLOAT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), - UNCOMPRESSED_FORMAT(/* R32G32B32A32_FLOAT */ FLOAT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), - - UNCOMPRESSED_FORMAT(/* S8_UINT */ UINT, STENCIL, 1, 1, LINEAR, STENCIL, RG(-1, 0)), - UNCOMPRESSED_FORMAT(/* D16_UNORM */ UNORM, DEPTH, 2, 2, LINEAR, DEPTH, RG(0, -1)), - UNCOMPRESSED_FORMAT(/* D32_FLOAT */ FLOAT, DEPTH, 4, 4, LINEAR, DEPTH, RG(0, -1)), - - UNCOMPRESSED_FORMAT(/* D16_UNORM_S8_UINT */ UNORM, DEPTH_STENCIL, 3, 2, LINEAR, DEPTH_STENCIL, RG(0, 2)), - UNCOMPRESSED_FORMAT(/* D24_UNORM_S8_UINT */ UNORM, DEPTH_STENCIL, 4, 3, LINEAR, DEPTH_STENCIL, RG(0, 3)), - UNCOMPRESSED_FORMAT(/* D32_FLOAT_S8_UINT */ FLOAT, DEPTH_STENCIL, 5, 4, LINEAR, DEPTH_STENCIL, RG(0, 4)), - - UNCOMPRESSED_FORMAT(/* R8_SRGB */ SRGB, COLOR, 1, 1, LINEAR, RED, R(0)), - UNCOMPRESSED_FORMAT(/* R8G8_SRBG */ SRGB, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), - UNCOMPRESSED_FORMAT(/* R8G8B8_SRBG */ SRGB, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), - UNCOMPRESSED_FORMAT(/* R8G8B8A8_SRBG */ SRGB, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), - UNCOMPRESSED_FORMAT(/* B8G8R8_SRBG */ SRGB, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), - UNCOMPRESSED_FORMAT(/* B8G8R8A8_SRBG */ SRGB, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), + // +----------------------------------------------------------------------------------------------------------+ + // | ,-> bytes per texel | + // | | ,-> bytes per component | + // | format name | type | aspect | | Layout | Components | Offsets | + UNCOMPRESSED_FORMAT(UNDEFINED, UNDEFINED, UNDEFINED, 0, 0, UNDEFINED, UNDEFINED, UNDEFINED), + UNCOMPRESSED_FORMAT(R8_SNORM, SNORM, COLOR, 1, 1, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R8G8_SNORM, SNORM, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), + UNCOMPRESSED_FORMAT(R8G8B8_SNORM, SNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), + UNCOMPRESSED_FORMAT(R8G8B8A8_SNORM, SNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), + UNCOMPRESSED_FORMAT(B8G8R8_SNORM, SNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), + UNCOMPRESSED_FORMAT(B8G8R8A8_SNORM, SNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), + + UNCOMPRESSED_FORMAT(R8_UNORM, UNORM, COLOR, 1, 1, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R8G8_UNORM, UNORM, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), + UNCOMPRESSED_FORMAT(R8G8B8_UNORM, UNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), + UNCOMPRESSED_FORMAT(R8G8B8A8_UNORM, UNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), + UNCOMPRESSED_FORMAT(B8G8R8_UNORM, UNORM, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), + UNCOMPRESSED_FORMAT(B8G8R8A8_UNORM, UNORM, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), + + UNCOMPRESSED_FORMAT(R8_SINT, SINT, COLOR, 1, 1, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R8G8_SINT, SINT, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), + UNCOMPRESSED_FORMAT(R8G8B8_SINT, SINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), + UNCOMPRESSED_FORMAT(R8G8B8A8_SINT, SINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), + UNCOMPRESSED_FORMAT(B8G8R8_SINT, SINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), + UNCOMPRESSED_FORMAT(B8G8R8A8_SINT, SINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), + + UNCOMPRESSED_FORMAT(R8_UINT, UINT, COLOR, 1, 1, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R8G8_UINT, UINT, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), + UNCOMPRESSED_FORMAT(R8G8B8_UINT, UINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), + UNCOMPRESSED_FORMAT(R8G8B8A8_UINT, UINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), + UNCOMPRESSED_FORMAT(B8G8R8_UINT, UINT, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), + UNCOMPRESSED_FORMAT(B8G8R8A8_UINT, UINT, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), + + UNCOMPRESSED_FORMAT(R16_SNORM, SNORM, COLOR, 2, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R16G16_SNORM, SNORM, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), + UNCOMPRESSED_FORMAT(R16G16B16_SNORM, SNORM, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), + UNCOMPRESSED_FORMAT(R16G16B16A16_SNORM, SNORM, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), + + UNCOMPRESSED_FORMAT(R16_UNORM, UNORM, COLOR, 2, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R16G16_UNORM, UNORM, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), + UNCOMPRESSED_FORMAT(R16G16B16_UNORM, UNORM, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), + UNCOMPRESSED_FORMAT(R16G16B16A16_UNORM, UNORM, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), + + UNCOMPRESSED_FORMAT(R16_SINT, SINT, COLOR, 2, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R16G16_SINT, SINT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), + UNCOMPRESSED_FORMAT(R16G16B16_SINT, SINT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), + UNCOMPRESSED_FORMAT(R16G16B16A16_SINT, SINT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), + + UNCOMPRESSED_FORMAT(R16_UINT, UINT, COLOR, 2, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R16G16_UINT, UINT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), + UNCOMPRESSED_FORMAT(R16G16B16_UINT, UINT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), + UNCOMPRESSED_FORMAT(R16G16B16A16_UINT, UINT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), + + UNCOMPRESSED_FORMAT(R16_FLOAT, FLOAT, COLOR, 2, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R16G16_FLOAT, FLOAT, COLOR, 4, 2, LINEAR, RED_GREEN, RG(0, 2)), + UNCOMPRESSED_FORMAT(R16G16B16_FLOAT, FLOAT, COLOR, 6, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 2, 4)), + UNCOMPRESSED_FORMAT(R16G16B16A16_FLOAT, FLOAT, COLOR, 8, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 2, 4, 6)), + + UNCOMPRESSED_FORMAT(R32_SINT, SINT, COLOR, 4, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R32G32_SINT, SINT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), + UNCOMPRESSED_FORMAT(R32G32B32_SINT, SINT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), + UNCOMPRESSED_FORMAT(R32G32B32A32_SINT, SINT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), + + UNCOMPRESSED_FORMAT(R32_UINT, UINT, COLOR, 4, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R32G32_UINT, UINT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), + UNCOMPRESSED_FORMAT(R32G32B32_UINT, UINT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), + UNCOMPRESSED_FORMAT(R32G32B32A32_UINT, UINT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), + + UNCOMPRESSED_FORMAT(R32_FLOAT, FLOAT, COLOR, 4, 2, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R32G32_FLOAT, FLOAT, COLOR, 8, 2, LINEAR, RED_GREEN, RG(0, 4)), + UNCOMPRESSED_FORMAT(R32G32B32_FLOAT, FLOAT, COLOR, 12, 2, LINEAR, RED_GREEN_BLUE, RGB(0, 4, 8)), + UNCOMPRESSED_FORMAT(R32G32B32A32_FLOAT, FLOAT, COLOR, 16, 2, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 4, 8, 12)), + + UNCOMPRESSED_FORMAT(S8_UINT, UINT, STENCIL, 1, 1, LINEAR, STENCIL, RG(-1, 0)), + UNCOMPRESSED_FORMAT(D16_UNORM, UNORM, DEPTH, 2, 2, LINEAR, DEPTH, RG(0, -1)), + UNCOMPRESSED_FORMAT(D32_FLOAT, FLOAT, DEPTH, 4, 4, LINEAR, DEPTH, RG(0, -1)), + + UNCOMPRESSED_FORMAT(D16_UNORM_S8_UINT, UNORM, DEPTH_STENCIL, 3, 2, LINEAR, DEPTH_STENCIL, RG(0, 2)), + UNCOMPRESSED_FORMAT(D24_UNORM_S8_UINT, UNORM, DEPTH_STENCIL, 4, 3, LINEAR, DEPTH_STENCIL, RG(0, 3)), + UNCOMPRESSED_FORMAT(D32_FLOAT_S8_UINT, FLOAT, DEPTH_STENCIL, 5, 4, LINEAR, DEPTH_STENCIL, RG(0, 4)), + + UNCOMPRESSED_FORMAT(R8_SRGB, SRGB, COLOR, 1, 1, LINEAR, RED, R(0)), + UNCOMPRESSED_FORMAT(R8G8_SRBG, SRGB, COLOR, 2, 1, LINEAR, RED_GREEN, RG(0, 1)), + UNCOMPRESSED_FORMAT(R8G8B8_SRBG, SRGB, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(0, 1, 2)), + UNCOMPRESSED_FORMAT(R8G8B8A8_SRBG, SRGB, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(0, 1, 2, 3)), + UNCOMPRESSED_FORMAT(B8G8R8_SRBG, SRGB, COLOR, 3, 1, LINEAR, RED_GREEN_BLUE, RGB(2, 1, 0)), + UNCOMPRESSED_FORMAT(B8G8R8A8_SRBG, SRGB, COLOR, 4, 1, LINEAR, RED_GREEN_BLUE_ALPHA, RGBA(2, 1, 0, 3)), // We don't support retrieving component size or byte offsets for packed formats. - UNCOMPRESSED_FORMAT(/* R10G10B10A2_UNORM */ UNORM, COLOR, 4, -1, PACKED, RED_GREEN_BLUE_ALPHA, UNDEFINED), - UNCOMPRESSED_FORMAT(/* R11G11B10_FLOAT */ FLOAT, COLOR, 4, -1, PACKED, RED_GREEN_BLUE, UNDEFINED), + UNCOMPRESSED_FORMAT(R10G10B10A2_UNORM, UNORM, COLOR, 4, -1, PACKED, RED_GREEN_BLUE_ALPHA, UNDEFINED), + UNCOMPRESSED_FORMAT(R11G11B10_FLOAT, FLOAT, COLOR, 4, -1, PACKED, RED_GREEN_BLUE, UNDEFINED), // We don't support retrieving component size or byte offsets for compressed formats. // We don't support non-square blocks for compressed textures. - // +----------------------------------------------------------+ - // | ,-> bytes per block | - // | | ,-> block width | - // | grfx format | type | | Components | - COMPRESSED_FORMAT(/* BC1_RGBA_SRGB */ SRGB, 8, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC1_RGBA_UNORM */ UNORM, 8, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC1_RGB_SRGB */ SRGB, 8, 4, RED_GREEN_BLUE), - COMPRESSED_FORMAT(/* BC1_RGB_UNORM */ UNORM, 8, 4, RED_GREEN_BLUE), - COMPRESSED_FORMAT(/* BC2_SRGB */ SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC2_UNORM */ UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC3_SRGB */ SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC3_UNORM */ UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC4_UNORM */ UNORM, 8, 4, RED), - COMPRESSED_FORMAT(/* BC4_SNORM */ SNORM, 8, 4, RED), - COMPRESSED_FORMAT(/* BC5_UNORM */ UNORM, 16, 4, RED_GREEN), - COMPRESSED_FORMAT(/* BC5_SNORM */ SNORM, 16, 4, RED_GREEN), - COMPRESSED_FORMAT(/* BC6H_UFLOAT */ FLOAT, 16, 4, RED_GREEN_BLUE), - COMPRESSED_FORMAT(/* BC6H_SFLOAT */ FLOAT, 16, 4, RED_GREEN_BLUE), - COMPRESSED_FORMAT(/* BC7_UNORM */ UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), - COMPRESSED_FORMAT(/* BC7_SRGB */ SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), + // +-----------------------------------------------------+ + // | ,-> bytes per block | + // | | ,-> block width | + // | format name | type | | Components | + COMPRESSED_FORMAT(BC1_RGBA_SRGB , SRGB, 8, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC1_RGBA_UNORM, UNORM, 8, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC1_RGB_SRGB , SRGB, 8, 4, RED_GREEN_BLUE), + COMPRESSED_FORMAT(BC1_RGB_UNORM , UNORM, 8, 4, RED_GREEN_BLUE), + COMPRESSED_FORMAT(BC2_SRGB , SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC2_UNORM , UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC3_SRGB , SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC3_UNORM , UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC4_UNORM , UNORM, 8, 4, RED), + COMPRESSED_FORMAT(BC4_SNORM , SNORM, 8, 4, RED), + COMPRESSED_FORMAT(BC5_UNORM , UNORM, 16, 4, RED_GREEN), + COMPRESSED_FORMAT(BC5_SNORM , SNORM, 16, 4, RED_GREEN), + COMPRESSED_FORMAT(BC6H_UFLOAT , FLOAT, 16, 4, RED_GREEN_BLUE), + COMPRESSED_FORMAT(BC6H_SFLOAT , FLOAT, 16, 4, RED_GREEN_BLUE), + COMPRESSED_FORMAT(BC7_UNORM , UNORM, 16, 4, RED_GREEN_BLUE_ALPHA), + COMPRESSED_FORMAT(BC7_SRGB , SRGB, 16, 4, RED_GREEN_BLUE_ALPHA), #undef COMPRESSED_FORMAT #undef UNCOMPRESSED_FORMAT @@ -190,5 +192,12 @@ const FormatDesc* GetFormatDescription(grfx::Format format) return &formatDescs[formatIndex]; } +const char* ToString(grfx::Format format) +{ + uint32_t formatIndex = static_cast(format); + PPX_ASSERT_MSG(formatIndex < formatDescsSize, "invalid format"); + return formatDescs[formatIndex].name; +} + } // namespace grfx } // namespace ppx