Skip to content

Commit

Permalink
Add multisample support for ShadingRatePattern.
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoeris authored and jorgeag-google committed Jul 18, 2024
1 parent 923280e commit 2fdb28f
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 44 deletions.
9 changes: 4 additions & 5 deletions include/ppx/grfx/grfx_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class DepthStencilView

grfx::ImagePtr GetImage() const { return mCreateInfo.pImage; }
grfx::Format GetFormat() const { return mCreateInfo.format; }
grfx::SampleCount GetSampleCount() const { return GetImage()->GetSampleCount(); }
uint32_t GetMipLevel() const { return mCreateInfo.mipLevel; }
uint32_t GetArrayLayer() const { return mCreateInfo.arrayLayer; }
grfx::AttachmentLoadOp GetDepthLoadOp() const { return mCreateInfo.depthLoadOp; }
Expand All @@ -230,7 +231,6 @@ struct RenderTargetViewCreateInfo
grfx::Image* pImage = nullptr;
grfx::ImageViewType imageViewType = grfx::IMAGE_VIEW_TYPE_UNDEFINED;
grfx::Format format = grfx::FORMAT_UNDEFINED;
grfx::SampleCount sampleCount = grfx::SAMPLE_COUNT_1;
uint32_t mipLevel = 0;
uint32_t mipLevelCount = 0;
uint32_t arrayLayer = 0;
Expand All @@ -256,7 +256,7 @@ class RenderTargetView

grfx::ImagePtr GetImage() const { return mCreateInfo.pImage; }
grfx::Format GetFormat() const { return mCreateInfo.format; }
grfx::SampleCount GetSampleCount() const { return mCreateInfo.sampleCount; }
grfx::SampleCount GetSampleCount() const { return GetImage()->GetSampleCount(); }
uint32_t GetMipLevel() const { return mCreateInfo.mipLevel; }
uint32_t GetArrayLayer() const { return mCreateInfo.arrayLayer; }
grfx::AttachmentLoadOp GetLoadOp() const { return mCreateInfo.loadOp; }
Expand Down Expand Up @@ -299,7 +299,7 @@ class SampledImageView
grfx::ImagePtr GetImage() const { return mCreateInfo.pImage; }
grfx::ImageViewType GetImageViewType() const { return mCreateInfo.imageViewType; }
grfx::Format GetFormat() const { return mCreateInfo.format; }
grfx::SampleCount GetSampleCount() const { return mCreateInfo.sampleCount; }
grfx::SampleCount GetSampleCount() const { return GetImage()->GetSampleCount(); }
uint32_t GetMipLevel() const { return mCreateInfo.mipLevel; }
uint32_t GetMipLevelCount() const { return mCreateInfo.mipLevelCount; }
uint32_t GetArrayLayer() const { return mCreateInfo.arrayLayer; }
Expand Down Expand Up @@ -341,7 +341,6 @@ struct StorageImageViewCreateInfo
grfx::Image* pImage = nullptr;
grfx::ImageViewType imageViewType = grfx::IMAGE_VIEW_TYPE_UNDEFINED;
grfx::Format format = grfx::FORMAT_UNDEFINED;
grfx::SampleCount sampleCount = grfx::SAMPLE_COUNT_1;
uint32_t mipLevel = 0;
uint32_t mipLevelCount = 0;
uint32_t arrayLayer = 0;
Expand All @@ -366,7 +365,7 @@ class StorageImageView
grfx::ImagePtr GetImage() const { return mCreateInfo.pImage; }
grfx::ImageViewType GetImageViewType() const { return mCreateInfo.imageViewType; }
grfx::Format GetFormat() const { return mCreateInfo.format; }
grfx::SampleCount GetSampleCount() const { return mCreateInfo.sampleCount; }
grfx::SampleCount GetSampleCount() const { return GetImage()->GetSampleCount(); }
uint32_t GetMipLevel() const { return mCreateInfo.mipLevel; }
uint32_t GetMipLevelCount() const { return mCreateInfo.mipLevelCount; }
uint32_t GetArrayLayer() const { return mCreateInfo.arrayLayer; }
Expand Down
23 changes: 19 additions & 4 deletions include/ppx/grfx/grfx_shading_rate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@
namespace ppx {
namespace grfx {

// Maximum number of supported shading rates in ShadingRateCapabilities.
static constexpr size_t kMaxSupportedShadingRateCount = 16;
// SupportedShadingRate
//
// A supported shading rate supported by the device.
struct SupportedShadingRate
{
// Bit mask of supported sample counts.
uint32_t sampleCountMask;

// Size of the shading rate fragment size.
Extent2D fragmentSize;
};

// ShadingRateCapabilities
//
Expand Down Expand Up @@ -53,8 +62,7 @@ struct ShadingRateCapabilities
Extent2D maxTexelSize;

// List of supported shading rates.
uint32_t supportedRateCount = 0;
Extent2D supportedRates[kMaxSupportedShadingRateCount];
std::vector<SupportedShadingRate> supportedRates;
} vrs;
};

Expand Down Expand Up @@ -94,6 +102,9 @@ struct ShadingRatePatternCreateInfo

// The shading rate mode (FDM or VRS).
ShadingRateMode shadingRateMode = SHADING_RATE_NONE;

// The sample count of the render targets using this shading rate pattern.
SampleCount sampleCount;
};

// ShadingRatePattern
Expand Down Expand Up @@ -121,6 +132,9 @@ class ShadingRatePattern
uint32_t GetTexelWidth() const { return mTexelSize.width; }
uint32_t GetTexelHeight() const { return mTexelSize.height; }

// The sample count of the render targets using this shading rate pattern.
SampleCount GetSampleCount() const { return mSampleCount; }

// Create a bitmap suitable for uploading fragment density/size to this pattern.
std::unique_ptr<Bitmap> CreateBitmap() const;

Expand All @@ -137,6 +151,7 @@ class ShadingRatePattern
ShadingRateMode mShadingRateMode;
ImagePtr mAttachmentImage;
Extent2D mTexelSize;
SampleCount mSampleCount;
};

} // namespace grfx
Expand Down
7 changes: 5 additions & 2 deletions include/ppx/grfx/vk/vk_shading_rate.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@ class FDMShadingRateEncoder : public grfx::ShadingRateEncoder
class VRSShadingRateEncoder : public grfx::ShadingRateEncoder
{
public:
void Initialize(const ShadingRateCapabilities& capabilities);
void Initialize(SampleCount sampleCount, const ShadingRateCapabilities& capabilities);
virtual ~VRSShadingRateEncoder() = default;
uint32_t EncodeFragmentDensity(uint8_t xDensity, uint8_t yDensity) const override;
uint32_t EncodeFragmentSize(uint8_t fragmentWidth, uint8_t fragmentHeight) const override;

private:
// Maximum encoded value of a shading rate.
static constexpr size_t kMaxEncodedShadingRate = (2 << 2) | 2;

uint32_t EncodeFragmentSizeImpl(uint8_t xDensity, uint8_t yDensity) const;
static uint32_t RawEncode(uint8_t width, uint8_t height);

Expand All @@ -62,7 +65,7 @@ class VRSShadingRateEncoder : public grfx::ShadingRateEncoder
// Ties are broken lexicographically, e.g. if 2x2, 1x4 and 4x1
// are supported, then 2x4 will be mapped to 2x2 but 4x2 will
// map to 4x1.
std::array<uint8_t, kMaxSupportedShadingRateCount> mMapRateToSupported;
std::array<uint8_t, kMaxEncodedShadingRate + 1> mMapRateToSupported;
};
} // namespace internal

Expand Down
3 changes: 0 additions & 3 deletions src/ppx/grfx/grfx_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ grfx::RenderTargetViewCreateInfo RenderTargetViewCreateInfo::GuessFromImage(grfx
ci.pImage = pImage;
ci.imageViewType = pImage->GuessImageViewType();
ci.format = pImage->GetFormat();
ci.sampleCount = pImage->GetSampleCount();
ci.mipLevel = 0;
ci.mipLevelCount = 1;
ci.arrayLayer = 0;
Expand All @@ -179,7 +178,6 @@ grfx::SampledImageViewCreateInfo SampledImageViewCreateInfo::GuessFromImage(grfx
ci.pImage = pImage;
ci.imageViewType = pImage->GuessImageViewType();
ci.format = pImage->GetFormat();
ci.sampleCount = pImage->GetSampleCount();
ci.mipLevel = 0;
ci.mipLevelCount = pImage->GetMipLevelCount();
ci.arrayLayer = 0;
Expand All @@ -198,7 +196,6 @@ grfx::StorageImageViewCreateInfo StorageImageViewCreateInfo::GuessFromImage(grfx
ci.pImage = pImage;
ci.imageViewType = pImage->GuessImageViewType();
ci.format = pImage->GetFormat();
ci.sampleCount = pImage->GetSampleCount();
ci.mipLevel = 0;
ci.mipLevelCount = pImage->GetMipLevelCount();
ci.arrayLayer = 0;
Expand Down
2 changes: 0 additions & 2 deletions src/ppx/grfx/grfx_render_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,6 @@ Result RenderPass::CreateImagesAndViewsV2(const grfx::internal::RenderPassCreate
rtvCreateInfo.pImage = image;
rtvCreateInfo.imageViewType = grfx::IMAGE_VIEW_TYPE_2D;
rtvCreateInfo.format = pCreateInfo->V2.renderTargetFormats[i];
rtvCreateInfo.sampleCount = image->GetSampleCount();
rtvCreateInfo.mipLevel = 0;
rtvCreateInfo.mipLevelCount = 1;
rtvCreateInfo.arrayLayer = 0;
Expand Down Expand Up @@ -412,7 +411,6 @@ Result RenderPass::CreateImagesAndViewsV3(const grfx::internal::RenderPassCreate
rtvCreateInfo.pImage = image;
rtvCreateInfo.imageViewType = image->GuessImageViewType();
rtvCreateInfo.format = image->GetFormat();
rtvCreateInfo.sampleCount = image->GetSampleCount();
rtvCreateInfo.mipLevel = 0;
rtvCreateInfo.mipLevelCount = image->GetMipLevelCount();
rtvCreateInfo.arrayLayer = 0;
Expand Down
17 changes: 8 additions & 9 deletions src/ppx/grfx/vk/vk_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,27 +470,26 @@ void Device::ConfigureVRSShadingRateCapabilities(
vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width,
vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height};

uint32_t& supportedRateCount = pShadingRateCapabilities->vrs.supportedRateCount;
Extent2D* supportedRates = pShadingRateCapabilities->vrs.supportedRates;

VkInstance instance = ToApi(GetInstance())->GetVkInstance();
mFnGetPhysicalDeviceFragmentShadingRatesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFragmentShadingRatesKHR"));
PPX_ASSERT_MSG(
mFnGetPhysicalDeviceFragmentShadingRatesKHR != nullptr,
"ConfigureVRSShadingRateCapabilities: Failed to load vkGetPhysicalDeviceFragmentShadingRatesKHR");

VkResult vkres = mFnGetPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedRateCount, nullptr);
uint32_t fragmentShadingRateCount = 0;
VkResult vkres = mFnGetPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &fragmentShadingRateCount, nullptr);
PPX_ASSERT_MSG(vkres == VK_SUCCESS, "vkGetPhysicalDeviceFragmentShadingRatesKHR failed");

std::vector<VkPhysicalDeviceFragmentShadingRateKHR> fragmentShadingRates(
supportedRateCount, VkPhysicalDeviceFragmentShadingRateKHR{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR});
vkres = mFnGetPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedRateCount, fragmentShadingRates.data());
fragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR});
vkres = mFnGetPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &fragmentShadingRateCount, fragmentShadingRates.data());
PPX_ASSERT_MSG(vkres == VK_SUCCESS, "vkGetPhysicalDeviceFragmentShadingRatesKHR failed");

for (uint32_t i = 0; i < supportedRateCount; ++i) {
const auto& rate = fragmentShadingRates[i];
supportedRates[i] = {rate.fragmentSize.width, rate.fragmentSize.height};
for (const auto& rate : fragmentShadingRates) {
auto& supportedRate = pShadingRateCapabilities->vrs.supportedRates.emplace_back();
supportedRate.sampleCountMask = rate.sampleCounts;
supportedRate.fragmentSize = {rate.fragmentSize.width, rate.fragmentSize.height};
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/ppx/grfx/vk/vk_render_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ Result RenderPass::CreateRenderPass(const grfx::internal::RenderPassCreateInfo*
}

if (!IsNull(pCreateInfo->pShadingRatePattern)) {
SampleCount shadingRateSampleCount = pCreateInfo->pShadingRatePattern->GetSampleCount();
for (uint32_t i = 0; i < rtvCount; ++i) {
PPX_ASSERT_MSG(
mRenderTargetViews[i]->GetSampleCount() == shadingRateSampleCount,
"The sample count for each render target must match the sample count of the shading rate pattern.");
}
if (hasDepthSencil) {
PPX_ASSERT_MSG(
mDepthStencilView->GetSampleCount() == shadingRateSampleCount,
"The sample count of the depth attachment must match the sample count of the shading rate pattern.");
}
auto modifiedCreateInfo = ToApi(pCreateInfo->pShadingRatePattern)->GetModifiedRenderPassCreateInfo(vkci);
VkResult vkres = vk::CreateRenderPass(
ToApi(GetDevice())->GetVkDevice(),
Expand Down
14 changes: 8 additions & 6 deletions src/ppx/grfx/vk/vk_shading_rate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,19 @@ uint32_t VRSShadingRateEncoder::RawEncode(uint8_t width, uint8_t height)
return (widthEnc << 2) | heightEnc;
}

void VRSShadingRateEncoder::Initialize(const ShadingRateCapabilities& capabilities)
void VRSShadingRateEncoder::Initialize(SampleCount sampleCount, const ShadingRateCapabilities& capabilities)
{
// Calculate the mapping from requested shading rates to supported shading rates.

// Initialize all shading rate values with UINT8_MAX to mark as unsupported.
std::fill(mMapRateToSupported.begin(), mMapRateToSupported.end(), UINT8_MAX);

// Supported shading rates map to themselves.
for (uint32_t i = 0; i < capabilities.vrs.supportedRateCount; ++i) {
auto rate = capabilities.vrs.supportedRates[i];
uint32_t encoded = RawEncode(rate.width, rate.height);
mMapRateToSupported[encoded] = encoded;
for (const auto& rate : capabilities.vrs.supportedRates) {
if ((rate.sampleCountMask & sampleCount) != 0) {
uint32_t encoded = RawEncode(rate.fragmentSize.width, rate.fragmentSize.height);
mMapRateToSupported[encoded] = encoded;
}
}

// Calculate the mapping for unsupported shading rates.
Expand Down Expand Up @@ -141,6 +142,7 @@ const ShadingRateEncoder* ShadingRatePattern::GetShadingRateEncoder() const
Result ShadingRatePattern::CreateApiObjects(const ShadingRatePatternCreateInfo* pCreateInfo)
{
mShadingRateMode = pCreateInfo->shadingRateMode;
mSampleCount = pCreateInfo->sampleCount;
const auto& capabilities = GetDevice()->GetShadingRateCapabilities();

grfx::ImageCreateInfo imageCreateInfo = {};
Expand All @@ -164,7 +166,7 @@ Result ShadingRatePattern::CreateApiObjects(const ShadingRatePatternCreateInfo*
imageCreateInfo.initialState = RESOURCE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT;

auto vrsShadingRateEncoder = std::make_unique<internal::VRSShadingRateEncoder>();
vrsShadingRateEncoder->Initialize(capabilities);
vrsShadingRateEncoder->Initialize(mSampleCount, capabilities);
mShadingRateEncoder = std::move(vrsShadingRateEncoder);
} break;
default:
Expand Down
47 changes: 34 additions & 13 deletions src/test/vk_shading_rate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ namespace ppx {
namespace grfx {
namespace vk {

ShadingRateCapabilities CreateTestCapabilities()
{
ShadingRateCapabilities capabilities = {SHADING_RATE_VRS};
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1 | SAMPLE_COUNT_4, {2, 2}});
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1 | SAMPLE_COUNT_4, {2, 1}});
capabilities.vrs.supportedRates.push_back({~0u, {1, 1}});
return capabilities;
}

TEST(VRSShadingRateEncoderTest, Only1x1)
{
ShadingRateCapabilities capabilities = {SHADING_RATE_VRS};
capabilities.vrs.supportedRateCount = 1;
capabilities.vrs.supportedRates[0] = {1, 1};
capabilities.vrs.supportedRates.push_back({~0u, {1, 1}});

internal::VRSShadingRateEncoder encoder;
encoder.Initialize(capabilities);
encoder.Initialize(SAMPLE_COUNT_1, capabilities);

EXPECT_EQ(encoder.EncodeFragmentSize(1, 1), 0);
EXPECT_EQ(encoder.EncodeFragmentSize(1, 2), 0);
Expand All @@ -45,13 +53,12 @@ TEST(VRSShadingRateEncoderTest, Only1x1)
TEST(VRSShadingRateEncoderTest, MultipleSizes)
{
ShadingRateCapabilities capabilities = {SHADING_RATE_VRS};
capabilities.vrs.supportedRateCount = 3;
capabilities.vrs.supportedRates[0] = {1, 2};
capabilities.vrs.supportedRates[1] = {2, 1};
capabilities.vrs.supportedRates[2] = {1, 1};
capabilities.vrs.supportedRates.push_back({~0u, {1, 2}});
capabilities.vrs.supportedRates.push_back({~0u, {2, 1}});
capabilities.vrs.supportedRates.push_back({~0u, {1, 1}});

internal::VRSShadingRateEncoder encoder;
encoder.Initialize(capabilities);
encoder.Initialize(SAMPLE_COUNT_1, capabilities);

EXPECT_EQ(encoder.EncodeFragmentSize(1, 1), 0);
EXPECT_EQ(encoder.EncodeFragmentSize(1, 2), 1);
Expand All @@ -64,16 +71,30 @@ TEST(VRSShadingRateEncoderTest, MultipleSizes)
EXPECT_EQ(encoder.EncodeFragmentSize(4, 4), 4);
}

TEST(VRSShadingRateEncoderTest, MultipleSampleCounts)
{
ShadingRateCapabilities capabilities = {SHADING_RATE_VRS};
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1, {1, 2}});
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1, {2, 1}});
capabilities.vrs.supportedRates.push_back({~0u, {1, 1}});

internal::VRSShadingRateEncoder encoder;
encoder.Initialize(SAMPLE_COUNT_2, capabilities);

EXPECT_EQ(encoder.EncodeFragmentSize(1, 1), 0);
EXPECT_EQ(encoder.EncodeFragmentSize(1, 2), 0);
EXPECT_EQ(encoder.EncodeFragmentSize(2, 1), 0);
}

TEST(VRSShadingRateEncoderTest, EncodeFragmentDensity)
{
ShadingRateCapabilities capabilities = {SHADING_RATE_VRS};
capabilities.vrs.supportedRateCount = 3;
capabilities.vrs.supportedRates[0] = {1, 2};
capabilities.vrs.supportedRates[1] = {2, 1};
capabilities.vrs.supportedRates[2] = {1, 1};
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1, {1, 2}});
capabilities.vrs.supportedRates.push_back({SAMPLE_COUNT_1, {2, 1}});
capabilities.vrs.supportedRates.push_back({~0u, {1, 1}});

internal::VRSShadingRateEncoder encoder;
encoder.Initialize(capabilities);
encoder.Initialize(SAMPLE_COUNT_1, capabilities);

EXPECT_EQ(encoder.EncodeFragmentDensity(255, 255), 0);
EXPECT_EQ(encoder.EncodeFragmentDensity(255, 127), 1);
Expand Down

0 comments on commit 2fdb28f

Please sign in to comment.