Vulkan: Add support for GL_QCOM_shading_rate

Layer GL_QCOM_shading_rate over VK_KHR_fragment_shading_rate

Test: ShadingRateQcomTest*
Bug: angleproject:7172
Change-Id: I3f040dbfad3906facd4349937fed2ce9a464b824
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3599874
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: mohan maiya <m.maiya@samsung.com>
This commit is contained in:
Mohan Maiya 2022-04-21 16:32:31 -07:00 коммит произвёл Angle LUCI CQ
Родитель 69705e5c0b
Коммит 02b968481a
22 изменённых файлов: 427 добавлений и 7 удалений

Просмотреть файл

@ -127,6 +127,10 @@ extern PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP
// VK_KHR_shared_presentable_image
extern PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR;
// VK_KHR_fragment_shading_rate
extern PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR;
extern PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR;
} // namespace rx
#endif // ANGLE_SHARED_LIBVULKAN

Просмотреть файл

@ -5866,7 +5866,7 @@ void Context::scissor(GLint x, GLint y, GLsizei width, GLsizei height)
void Context::shadingRateQCOM(GLenum rate)
{
return;
mState.setShadingRate(rate);
}
void Context::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)

Просмотреть файл

@ -356,6 +356,7 @@ MSG kInvalidShaderBinaryFormat = "Invalid shader binary format.";
MSG kInvalidShaderName = "Shader object expected.";
MSG kInvalidShaderType = "Invalid shader type.";
MSG kInvalidShadingModel = "Invalid shading model.";
MSG kInvalidShadingRate = "Invalid shading rate.";
MSG kInvalidSourceTexture = "Source texture is not a valid texture object.";
MSG kInvalidSourceTextureInternalFormat = "Source texture internal format is invalid.";
MSG kInvalidSourceTextureLevel = "Invalid source texture level.";
@ -504,6 +505,7 @@ MSG kShaderAttachmentHasShader = "Shader attachment already has a shader.";
MSG kShaderSourceInvalidCharacters = "Shader source contains invalid characters.";
MSG kShaderStorageBufferOffsetAlignment = "Offset must be multiple of value of SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT.";
MSG kShaderToDetachMustBeAttached = "Shader to be detached must be currently attached to the program.";
MSG kShadingRateExtensionNotAvailable = "GL_QCOM_shading_rate extension not available.";
MSG kSourceLevelNotDefined = "The source level of the source texture must be defined.";
MSG kSourceTextureLevelZeroDefined = "Source texture must level 0 defined.";
MSG kSourceTextureMustBeCompressed = "Source texture must have a compressed internal format.";

Просмотреть файл

@ -418,7 +418,9 @@ State::State(const State *shareContextState,
mBoundingBoxMaxX(1.0f),
mBoundingBoxMaxY(1.0f),
mBoundingBoxMaxZ(1.0f),
mBoundingBoxMaxW(1.0f)
mBoundingBoxMaxW(1.0f),
mShadingRatePreserveAspectRatio(false),
mShadingRate(ShadingRate::_1x1)
{}
State::~State() {}
@ -1336,6 +1338,10 @@ void State::setEnableFeature(GLenum feature, bool enabled)
setClipDistanceEnable(feature - GL_CLIP_DISTANCE0_EXT, enabled);
return;
}
break;
case GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM:
mShadingRatePreserveAspectRatio = enabled;
return;
}
ASSERT(mClientVersion.major == 1);
@ -1481,6 +1487,8 @@ bool State::getEnableFeature(GLenum feature) const
return mClipDistancesEnabled.test(feature - GL_CLIP_DISTANCE0_EXT);
}
break;
case GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM:
return mShadingRatePreserveAspectRatio;
}
ASSERT(mClientVersion.major == 1);
@ -2366,6 +2374,13 @@ void State::setPatchVertices(GLuint value)
}
}
void State::setShadingRate(GLenum rate)
{
mShadingRate = FromGLenum<ShadingRate>(rate);
mDirtyBits.set(DIRTY_BIT_EXTENDED);
mExtendedDirtyBits.set(EXTENDED_DIRTY_BIT_SHADING_RATE);
}
void State::getBooleanv(GLenum pname, GLboolean *params) const
{
switch (pname)
@ -3080,6 +3095,12 @@ angle::Result State::getIntegerv(const Context *context, GLenum pname, GLint *pa
case GL_CLIP_DEPTH_MODE_EXT:
*params = mClipControlDepth;
break;
// GL_QCOM_shading_rate
case GL_SHADING_RATE_QCOM:
*params = ToGLenum(mShadingRate);
break;
default:
UNREACHABLE();
break;

Просмотреть файл

@ -362,6 +362,10 @@ class State : angle::NonCopyable
return mVertexArray;
}
// QCOM_shading_rate helpers
void setShadingRate(GLenum rate);
ShadingRate getShadingRate() const { return mShadingRate; }
// If both a Program and a ProgramPipeline are bound, the Program will
// always override the ProgramPipeline.
ProgramExecutable *getProgramExecutable() const { return mExecutable; }
@ -689,6 +693,7 @@ class State : angle::NonCopyable
EXTENDED_DIRTY_BIT_CLIP_DISTANCES, // clip distances
EXTENDED_DIRTY_BIT_MIPMAP_GENERATION_HINT, // mipmap generation hint
EXTENDED_DIRTY_BIT_SHADER_DERIVATIVE_HINT, // shader derivative hint
EXTENDED_DIRTY_BIT_SHADING_RATE, // QCOM_shading_rate
EXTENDED_DIRTY_BIT_INVALID,
EXTENDED_DIRTY_BIT_MAX = EXTENDED_DIRTY_BIT_INVALID,
};
@ -1168,6 +1173,10 @@ class State : angle::NonCopyable
GLfloat mBoundingBoxMaxY;
GLfloat mBoundingBoxMaxZ;
GLfloat mBoundingBoxMaxW;
// QCOM_shading_rate
bool mShadingRatePreserveAspectRatio;
ShadingRate mShadingRate;
};
ANGLE_INLINE angle::Result State::syncDirtyObjects(const Context *context,

Просмотреть файл

@ -3336,6 +3336,14 @@ bool GetQueryParameterInfo(const State &glState,
*type = GL_FLOAT;
*numParams = 8;
return true;
case GL_SHADING_RATE_QCOM:
if (!extensions.shadingRateQCOM)
{
return false;
}
*type = GL_INT;
*numParams = 1;
return true;
}
if (clientType == EGL_OPENGL_API ||

Просмотреть файл

@ -804,6 +804,10 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
{
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
}
if (getFeatures().supportsFragmentShadingRate.enabled)
{
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_SHADING_RATE);
}
mNewComputeCommandBufferDirtyBits =
DirtyBits{DIRTY_BIT_PIPELINE_BINDING, DIRTY_BIT_TEXTURES, DIRTY_BIT_SHADER_RESOURCES,
@ -855,8 +859,9 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
&ContextVk::handleDirtyGraphicsDescriptorSets;
mGraphicsDirtyBitHandlers[DIRTY_BIT_VIEWPORT] = &ContextVk::handleDirtyGraphicsViewport;
mGraphicsDirtyBitHandlers[DIRTY_BIT_SCISSOR] = &ContextVk::handleDirtyGraphicsScissor;
mGraphicsDirtyBitHandlers[DIRTY_BIT_VIEWPORT] = &ContextVk::handleDirtyGraphicsViewport;
mGraphicsDirtyBitHandlers[DIRTY_BIT_SCISSOR] = &ContextVk::handleDirtyGraphicsScissor;
mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADING_RATE] = &ContextVk::handleDirtyGraphicsShadingRate;
mComputeDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
&ContextVk::handleDirtyComputeMemoryBarrier;
@ -2424,6 +2429,75 @@ angle::Result ContextVk::handleDirtyGraphicsScissor(DirtyBits::Iterator *dirtyBi
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsShadingRate(DirtyBits::Iterator *dirtyBitsIterator,
DirtyBits dirtyBitMask)
{
gl::ShadingRate shadingRate = getState().getShadingRate();
const bool shadingRateSupported = mRenderer->isShadingRateSupported(shadingRate);
VkExtent2D fragmentSize = {};
VkFragmentShadingRateCombinerOpKHR shadingRateCombinerOp[2] = {
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR};
switch (shadingRate)
{
case gl::ShadingRate::_1x1:
ASSERT(shadingRateSupported);
fragmentSize.width = 1;
fragmentSize.height = 1;
break;
case gl::ShadingRate::_1x2:
ASSERT(shadingRateSupported);
fragmentSize.width = 1;
fragmentSize.height = 2;
break;
case gl::ShadingRate::_2x1:
ASSERT(shadingRateSupported);
fragmentSize.width = 2;
fragmentSize.height = 1;
break;
case gl::ShadingRate::_2x2:
ASSERT(shadingRateSupported);
fragmentSize.width = 2;
fragmentSize.height = 2;
break;
case gl::ShadingRate::_4x2:
if (shadingRateSupported)
{
fragmentSize.width = 4;
fragmentSize.height = 2;
}
else
{
// Fallback to shading rate that preserves aspect ratio
fragmentSize.width = 2;
fragmentSize.height = 1;
}
break;
case gl::ShadingRate::_4x4:
if (shadingRateSupported)
{
fragmentSize.width = 4;
fragmentSize.height = 4;
}
else
{
// Fallback to shading rate that preserves aspect ratio
fragmentSize.width = 2;
fragmentSize.height = 2;
}
break;
default:
UNREACHABLE();
return angle::Result::Stop;
}
ASSERT(hasStartedRenderPass());
mRenderPassCommandBuffer->setShadingRate(&fragmentSize, shadingRateCombinerOp);
return angle::Result::Continue;
}
void ContextVk::handleDirtyGraphicsScissorImpl(bool isPrimitivesGeneratedQueryActive)
{
// If primitives generated query and rasterizer discard are both active, but the Vulkan
@ -4619,6 +4693,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
case gl::State::ExtendedDirtyBitType::
EXTENDED_DIRTY_BIT_SHADER_DERIVATIVE_HINT:
break;
case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_SHADING_RATE:
mGraphicsDirtyBits.set(DIRTY_BIT_SHADING_RATE);
break;
default:
UNREACHABLE();
}

Просмотреть файл

@ -790,9 +790,10 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER,
DIRTY_BIT_BLEND_BARRIER,
// Dynamic viewport/scissor
// Dynamic viewport/scissor/shading rate
DIRTY_BIT_VIEWPORT,
DIRTY_BIT_SCISSOR,
DIRTY_BIT_SHADING_RATE,
DIRTY_BIT_MAX,
};
@ -849,6 +850,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
"Render pass using dirty bit must be handled after the render pass dirty bit");
static_assert(DIRTY_BIT_SCISSOR > DIRTY_BIT_RENDER_PASS,
"Render pass using dirty bit must be handled after the render pass dirty bit");
static_assert(DIRTY_BIT_SHADING_RATE > DIRTY_BIT_RENDER_PASS,
"Render pass using dirty bit must be handled after the render pass dirty bit");
using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
@ -1043,6 +1046,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
DirtyBits dirtyBitMask);
angle::Result handleDirtyGraphicsScissor(DirtyBits::Iterator *dirtyBitsIterator,
DirtyBits dirtyBitMask);
angle::Result handleDirtyGraphicsShadingRate(DirtyBits::Iterator *dirtyBitsIterator,
DirtyBits dirtyBitMask);
// Handlers for compute pipeline dirty bits.
angle::Result handleDirtyComputeMemoryBarrier();

Просмотреть файл

@ -1109,6 +1109,32 @@ angle::Result GetAndDecompressPipelineCacheVk(VkPhysicalDeviceProperties physica
// Environment variable (and associated Android property) to enable Vulkan debug-utils markers
constexpr char kEnableDebugMarkersVarName[] = "ANGLE_ENABLE_DEBUG_MARKERS";
constexpr char kEnableDebugMarkersPropertyName[] = "debug.angle.markers";
ANGLE_INLINE gl::ShadingRate GetShadingRateFromVkExtent(const VkExtent2D &extent)
{
if (extent.width == 1 && extent.height == 2)
{
return gl::ShadingRate::_1x2;
}
else if (extent.width == 2 && extent.height == 1)
{
return gl::ShadingRate::_2x1;
}
else if (extent.width == 2 && extent.height == 2)
{
return gl::ShadingRate::_2x2;
}
else if (extent.width == 4 && extent.height == 2)
{
return gl::ShadingRate::_4x2;
}
else if (extent.width == 4 && extent.height == 4)
{
return gl::ShadingRate::_4x4;
}
return gl::ShadingRate::_1x1;
}
} // namespace
// RendererVk implementation.
@ -1867,6 +1893,10 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
mBlendOperationAdvancedFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
mFragmentShadingRateFeatures = {};
mFragmentShadingRateFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
if (!vkGetPhysicalDeviceProperties2KHR || !vkGetPhysicalDeviceFeatures2KHR)
{
return;
@ -1999,6 +2029,11 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
vk::AddToPNextChain(&deviceFeatures, &mBlendOperationAdvancedFeatures);
}
if (ExtensionFound(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mFragmentShadingRateFeatures);
}
vkGetPhysicalDeviceFeatures2KHR(mPhysicalDevice, &deviceFeatures);
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
@ -2026,6 +2061,7 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
mHostQueryResetFeatures.pNext = nullptr;
mDepthClipControlFeatures.pNext = nullptr;
mBlendOperationAdvancedFeatures.pNext = nullptr;
mFragmentShadingRateFeatures.pNext = nullptr;
}
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
@ -2477,6 +2513,12 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vk::AddToPNextChain(&mEnabledFeatures, &mBlendOperationAdvancedFeatures);
}
if (getFeatures().supportsFragmentShadingRate.enabled)
{
mEnabledDeviceExtensions.push_back(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
vk::AddToPNextChain(&mEnabledFeatures, &mFragmentShadingRateFeatures);
}
mCurrentQueueFamilyIndex = queueFamilyIndex;
vk::QueueFamily queueFamily;
@ -2851,6 +2893,61 @@ gl::Version RendererVk::getMaxConformantESVersion() const
return maxSupportedESVersion;
}
bool RendererVk::canSupportFragmentShadingRate(const vk::ExtensionNameList &deviceExtensionNames)
{
// Device needs to support VK_KHR_fragment_shading_rate and specifically
// pipeline fragment shading rate.
if (mFragmentShadingRateFeatures.pipelineFragmentShadingRate != VK_TRUE)
{
return false;
}
// Init required functions
#if !defined(ANGLE_SHARED_LIBVULKAN)
InitFragmentShadingRateKHRFunctions(mDevice);
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
ASSERT(vkGetPhysicalDeviceFragmentShadingRatesKHR);
ASSERT(vkCmdSetFragmentShadingRateKHR);
// Query supported shading rates
constexpr uint32_t kShadingRatesCount = 6;
uint32_t shadingRatesCount = 6;
std::array<VkPhysicalDeviceFragmentShadingRateKHR, kShadingRatesCount> shadingRates = {
{{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {1, 1}},
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {1, 2}},
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {2, 1}},
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {2, 2}},
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {4, 2}},
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, nullptr, 0, {4, 4}}}};
VkResult result = vkGetPhysicalDeviceFragmentShadingRatesKHR(
mPhysicalDevice, &shadingRatesCount, shadingRates.data());
ASSERT(result == VK_SUCCESS || result == VK_INCOMPLETE);
ASSERT(shadingRatesCount > 0 && shadingRatesCount <= kShadingRatesCount);
// Cache supported fragment shading rates
mSupportedFragmentShadingRates.reset();
for (const VkPhysicalDeviceFragmentShadingRateKHR &shadingRate : shadingRates)
{
if (shadingRate.sampleCounts == 0)
{
continue;
}
mSupportedFragmentShadingRates.set(GetShadingRateFromVkExtent(shadingRate.fragmentSize));
}
// To implement GL_QCOM_shading_rate extension the Vulkan ICD needs to support at least the
// following shading rates -
// {1, 1}
// {1, 2}
// {2, 1}
// {2, 2}
return mSupportedFragmentShadingRates.test(gl::ShadingRate::_1x1) &&
mSupportedFragmentShadingRates.test(gl::ShadingRate::_1x2) &&
mSupportedFragmentShadingRates.test(gl::ShadingRate::_2x1) &&
mSupportedFragmentShadingRates.test(gl::ShadingRate::_2x2);
}
void RendererVk::initFeatures(DisplayVk *displayVk,
const vk::ExtensionNameList &deviceExtensionNames)
{
@ -3344,6 +3441,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
// host visible flag for them and result in allocation failure.
ANGLE_FEATURE_CONDITION(&mFeatures, preferDeviceLocalMemoryHostVisible, !isDiscreteGPU);
// Support GL_QCOM_shading_rate extension
ANGLE_FEATURE_CONDITION(&mFeatures, supportsFragmentShadingRate,
canSupportFragmentShadingRate(deviceExtensionNames));
ApplyFeatureOverrides(&mFeatures, displayVk->getState());
// Disable async command queue when using Vulkan secondary command buffers temporarily to avoid

Просмотреть файл

@ -563,6 +563,11 @@ class RendererVk : angle::NonCopyable
void addBufferBlockToOrphanList(vk::BufferBlock *block);
void pruneOrphanedBufferBlocks();
bool isShadingRateSupported(gl::ShadingRate shadingRate) const
{
return mSupportedFragmentShadingRates.test(shadingRate);
}
private:
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
@ -586,6 +591,9 @@ class RendererVk : angle::NonCopyable
// Initialize VMA allocator and buffer suballocator related data.
angle::Result initializeMemoryAllocator(DisplayVk *displayVk);
// Query and cache supported fragment shading rates
bool canSupportFragmentShadingRate(const vk::ExtensionNameList &deviceExtensionNames);
egl::Display *mDisplay;
void *mLibVulkanLibrary;
@ -639,6 +647,8 @@ class RendererVk : angle::NonCopyable
VkPhysicalDeviceDepthClipControlFeaturesEXT mDepthClipControlFeatures;
VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT mBlendOperationAdvancedFeatures;
VkPhysicalDeviceSamplerYcbcrConversionFeatures mSamplerYcbcrConversionFeatures;
VkPhysicalDeviceFragmentShadingRateFeaturesKHR mFragmentShadingRateFeatures;
angle::PackedEnumBitSet<gl::ShadingRate, uint8_t> mSupportedFragmentShadingRates;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
uint32_t mMaxVertexAttribDivisor;
uint32_t mCurrentQueueFamilyIndex;

Просмотреть файл

@ -122,6 +122,8 @@ const char *GetCommandString(CommandID id)
return "WaitEvents";
case CommandID::WriteTimestamp:
return "WriteTimestamp";
case CommandID::SetShadingRate:
return "SetShadingRate";
default:
// Need this to work around MSVC warning 4715.
UNREACHABLE();
@ -575,6 +577,17 @@ void SecondaryCommandBuffer::executeCommands(PrimaryCommandBuffer *primary)
params->query);
break;
}
case CommandID::SetShadingRate:
{
const SetShadingRateParams *params =
getParamPtr<SetShadingRateParams>(currentCommand);
const VkExtent2D fragmentSize = {params->fragmentWidth, params->fragmentHeight};
const VkFragmentShadingRateCombinerOpKHR ops[2] = {
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR};
vkCmdSetFragmentShadingRateKHR(cmdBuffer, &fragmentSize, ops);
break;
}
default:
{
UNREACHABLE();

Просмотреть файл

@ -83,6 +83,7 @@ enum class CommandID : uint16_t
SetViewport,
WaitEvents,
WriteTimestamp,
SetShadingRate,
};
#define VERIFY_4_BYTE_ALIGNMENT(StructName) \
@ -448,6 +449,13 @@ struct WriteTimestampParams
};
VERIFY_4_BYTE_ALIGNMENT(WriteTimestampParams)
struct SetShadingRateParams
{
uint16_t fragmentWidth;
uint16_t fragmentHeight;
};
VERIFY_4_BYTE_ALIGNMENT(SetShadingRateParams)
// Header for every cmd in custom cmd buffer
struct CommandHeader
{
@ -691,6 +699,8 @@ class SecondaryCommandBuffer final : angle::NonCopyable
const QueryPool &queryPool,
uint32_t query);
void setShadingRate(const VkExtent2D *fragmentSize, VkFragmentShadingRateCombinerOpKHR ops[2]);
// No-op for compatibility
VkResult end() { return VK_SUCCESS; }
@ -1514,6 +1524,25 @@ ANGLE_INLINE void SecondaryCommandBuffer::writeTimestamp(VkPipelineStageFlagBits
paramStruct->queryPool = queryPool.getHandle();
paramStruct->query = query;
}
ANGLE_INLINE void SecondaryCommandBuffer::setShadingRate(const VkExtent2D *fragmentSize,
VkFragmentShadingRateCombinerOpKHR ops[2])
{
ASSERT(fragmentSize != nullptr);
// Supported parameter values -
// 1. CombinerOp needs to be VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR
// 2. The largest fragment size supported is 4x4
ASSERT(ops[0] == VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR);
ASSERT(ops[1] == VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR);
ASSERT(fragmentSize->width <= 4);
ASSERT(fragmentSize->height <= 4);
SetShadingRateParams *paramStruct =
initCommand<SetShadingRateParams>(CommandID::SetShadingRate);
paramStruct->fragmentWidth = static_cast<uint16_t>(fragmentSize->width);
paramStruct->fragmentHeight = static_cast<uint16_t>(fragmentSize->height);
}
} // namespace priv
} // namespace vk
} // namespace rx

Просмотреть файл

@ -2316,9 +2316,13 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
}
// Dynamic state
angle::FixedVector<VkDynamicState, 2> dynamicStateList;
angle::FixedVector<VkDynamicState, 3> dynamicStateList;
dynamicStateList.push_back(VK_DYNAMIC_STATE_VIEWPORT);
dynamicStateList.push_back(VK_DYNAMIC_STATE_SCISSOR);
if (contextVk->getFeatures().supportsFragmentShadingRate.enabled)
{
dynamicStateList.push_back(VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR);
}
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;

Просмотреть файл

@ -1127,6 +1127,9 @@ void RendererVk::ensureCapsInitialized() const
// GL_KHR_parallel_shader_compile
mNativeExtensions.parallelShaderCompileKHR = false;
// GL_QCOM_shading_rate
mNativeExtensions.shadingRateQCOM = mFeatures.supportsFragmentShadingRate.enabled;
}
namespace vk

Просмотреть файл

@ -973,6 +973,10 @@ PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = null
// VK_KHR_shared_presentable_image
PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR = nullptr;
// VK_KHR_fragment_shading_rate
PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR = nullptr;
PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR = nullptr;
void InitDebugUtilsEXTFunctions(VkInstance instance)
{
GET_INSTANCE_FUNC(vkCreateDebugUtilsMessengerEXT);
@ -1094,6 +1098,13 @@ void InitGetSwapchainStatusKHRFunctions(VkDevice device)
GET_DEVICE_FUNC(vkGetSwapchainStatusKHR);
}
// VK_KHR_fragment_shading_rate
void InitFragmentShadingRateKHRFunctions(VkDevice device)
{
GET_DEVICE_FUNC(vkGetPhysicalDeviceFragmentShadingRatesKHR);
GET_DEVICE_FUNC(vkCmdSetFragmentShadingRateKHR);
}
# undef GET_INSTANCE_FUNC
# undef GET_DEVICE_FUNC

Просмотреть файл

@ -1319,6 +1319,9 @@ void InitExternalSemaphoreCapabilitiesFunctions(VkInstance instance);
// VK_KHR_shared_presentable_image
void InitGetSwapchainStatusKHRFunctions(VkDevice device);
// VK_KHR_fragment_shading_rate
void InitFragmentShadingRateKHRFunctions(VkDevice device);
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
GLenum CalculateGenerateMipmapFilter(ContextVk *contextVk, angle::FormatID formatID);

Просмотреть файл

@ -344,6 +344,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
void writeTimestamp(VkPipelineStageFlagBits pipelineStage,
const QueryPool &queryPool,
uint32_t query);
void setShadingRate(const VkExtent2D *fragmentSize, VkFragmentShadingRateCombinerOpKHR ops[2]);
// VK_EXT_transform_feedback
void beginTransformFeedback(uint32_t firstCounterBuffer,
@ -1034,6 +1035,13 @@ ANGLE_INLINE void CommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipeline
vkCmdWriteTimestamp(mHandle, pipelineStage, queryPool.getHandle(), query);
}
ANGLE_INLINE void CommandBuffer::setShadingRate(const VkExtent2D *fragmentSize,
VkFragmentShadingRateCombinerOpKHR ops[2])
{
ASSERT(valid() && fragmentSize != nullptr);
vkCmdSetFragmentShadingRateKHR(mHandle, fragmentSize, ops);
}
ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,

Просмотреть файл

@ -3012,6 +3012,14 @@ bool ValidateStateQuery(const Context *context,
}
break;
case GL_SHADING_RATE_QCOM:
if (!context->getExtensions().shadingRateQCOM)
{
context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
return false;
}
break;
default:
break;
}

Просмотреть файл

@ -632,6 +632,8 @@ bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
break;
case GL_SAMPLE_SHADING:
return context->getExtensions().sampleShadingOES;
case GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM:
return context->getExtensions().shadingRateQCOM;
}
// GLES1 emulation: GLES1-specific caps after this point

Просмотреть файл

@ -3033,6 +3033,18 @@ bool ValidateSelectPerfMonitorCountersAMD(const Context *context,
bool ValidateShadingRateQCOM(const Context *context, angle::EntryPoint entryPoint, GLenum rate)
{
return false;
if (!context->getExtensions().shadingRateQCOM)
{
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
return false;
}
if (gl::FromGLenum<gl::ShadingRate>(rate) == gl::ShadingRate::InvalidEnum)
{
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidShadingRate);
return false;
}
return true;
}
} // namespace gl

Просмотреть файл

@ -131,6 +131,7 @@ angle_end2end_tests_sources = [
"gl_tests/ShaderInterpTest.cpp",
"gl_tests/ShaderNonConstGlobalInitializerTest.cpp",
"gl_tests/ShaderStorageBufferTest.cpp",
"gl_tests/ShadingRateQcomTest.cpp",
"gl_tests/SimpleOperationTest.cpp",
"gl_tests/SixteenBppTextureTest.cpp",
"gl_tests/StateChangeTest.cpp",

Просмотреть файл

@ -0,0 +1,89 @@
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ShadingRateQcomTest.cpp : Tests of the GL_QCOM_shading_rate extension.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
namespace angle
{
class ShadingRateQcomTest : public ANGLETest
{
protected:
ShadingRateQcomTest()
{
setWindowWidth(256);
setWindowHeight(256);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// Test basic functionality of QCOM_shading_rate
TEST_P(ShadingRateQcomTest, Basic)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_shading_rate"));
glClearColor(0.25f, 0.5f, 0.5f, 0.5f);
glShadingRateQCOM(GL_SHADING_RATE_1X1_PIXELS_QCOM);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 128, 1.0);
ANGLE_GL_PROGRAM(uniformColorProgram, essl1_shaders::vs::Simple(),
essl1_shaders::fs::UniformColor());
glUseProgram(uniformColorProgram);
GLint colorUniformLocation =
glGetUniformLocation(uniformColorProgram, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
glShadingRateQCOM(GL_SHADING_RATE_1X2_PIXELS_QCOM);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glShadingRateQCOM(GL_SHADING_RATE_2X1_PIXELS_QCOM);
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glShadingRateQCOM(GL_SHADING_RATE_2X2_PIXELS_QCOM);
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
glShadingRateQCOM(GL_SHADING_RATE_4X2_PIXELS_QCOM);
glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
glShadingRateQCOM(GL_SHADING_RATE_4X4_PIXELS_QCOM);
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 1.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
glEnable(GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 1.0f, 1.0f);
drawQuad(uniformColorProgram, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShadingRateQcomTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(ShadingRateQcomTest);
} // namespace angle