зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
69705e5c0b
Коммит
02b968481a
|
@ -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,
|
||||
|
@ -857,6 +861,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
|
|||
|
||||
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)
|
||||
{
|
||||
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
|
Загрузка…
Ссылка в новой задаче