Commit a8a2a71b by Jamie Madill Committed by Commit Bot

Vulkan: Support y-flip with no driver support.

We can reuse the surface rotation matrix code to do the y-flip. This requires the SPIR-V transformation support. Because not all rotations are encoded into the table we can only support rotation with the driver support for y-flip (currently). Includes some very minimal regression testing. This work is targeted towards supporting vk-portability implementations which are not as up-to-date with Vulkan features. Bug: angleproject:5596 Change-Id: I270fa1efc03267551d28df33ddac9972e1343d60 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2665892Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 4e1b46d3
...@@ -467,6 +467,10 @@ struct FeaturesVk : FeatureSetBase ...@@ -467,6 +467,10 @@ struct FeaturesVk : FeatureSetBase
"emulateR32fImageAtomicExchange", FeatureCategory::VulkanWorkarounds, "emulateR32fImageAtomicExchange", FeatureCategory::VulkanWorkarounds,
"Emulate r32f images with r32ui to support imageAtomicExchange.", &members, "Emulate r32f images with r32ui to support imageAtomicExchange.", &members,
"http://anglebug.com/5535"}; "http://anglebug.com/5535"};
Feature supportsNegativeViewport = {
"supportsNegativeViewport", FeatureCategory::VulkanFeatures,
"The driver supports inverting the viewport with a negative height.", &members};
}; };
inline FeaturesVk::FeaturesVk() = default; inline FeaturesVk::FeaturesVk() = default;
......
...@@ -1807,12 +1807,28 @@ void SpirvTransformer::preRotateXY(spirv::IdRef xId, ...@@ -1807,12 +1807,28 @@ void SpirvTransformer::preRotateXY(spirv::IdRef xId,
switch (mOptions.preRotation) switch (mOptions.preRotation)
{ {
case SurfaceRotation::Identity: case SurfaceRotation::Identity:
case SurfaceRotation::FlippedIdentity:
// [ 1 0] [x] // [ 1 0] [x]
// [ 0 1] * [y] // [ 0 1] * [y]
*rotatedXIdOut = xId; *rotatedXIdOut = xId;
*rotatedYIdOut = yId; *rotatedYIdOut = yId;
break; break;
case SurfaceRotation::FlippedIdentity:
if (mOptions.negativeViewportSupported)
{
// [ 1 0] [x]
// [ 0 1] * [y]
*rotatedXIdOut = xId;
*rotatedYIdOut = yId;
}
else
{
// [ 1 0] [x]
// [ 0 -1] * [y]
*rotatedXIdOut = xId;
*rotatedYIdOut = getNewId();
spirv::WriteFNegate(mSpirvBlobOut, mFloatId, *rotatedYIdOut, yId);
}
break;
case SurfaceRotation::Rotated90Degrees: case SurfaceRotation::Rotated90Degrees:
case SurfaceRotation::FlippedRotated90Degrees: case SurfaceRotation::FlippedRotated90Degrees:
// [ 0 1] [x] // [ 0 1] [x]
......
...@@ -60,6 +60,7 @@ struct GlslangSpirvOptions ...@@ -60,6 +60,7 @@ struct GlslangSpirvOptions
{ {
gl::ShaderType shaderType = gl::ShaderType::InvalidEnum; gl::ShaderType shaderType = gl::ShaderType::InvalidEnum;
SurfaceRotation preRotation = SurfaceRotation::Identity; SurfaceRotation preRotation = SurfaceRotation::Identity;
bool negativeViewportSupported = false;
bool transformPositionToVulkanClipSpace = false; bool transformPositionToVulkanClipSpace = false;
bool removeEarlyFragmentTestsOptimization = false; bool removeEarlyFragmentTestsOptimization = false;
bool removeDebugInfo = false; bool removeDebugInfo = false;
......
...@@ -2634,8 +2634,7 @@ gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) con ...@@ -2634,8 +2634,7 @@ gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) con
void ContextVk::updateViewport(FramebufferVk *framebufferVk, void ContextVk::updateViewport(FramebufferVk *framebufferVk,
const gl::Rectangle &viewport, const gl::Rectangle &viewport,
float nearPlane, float nearPlane,
float farPlane, float farPlane)
bool invertViewport)
{ {
gl::Box fbDimensions = framebufferVk->getState().getDimensions(); gl::Box fbDimensions = framebufferVk->getState().getDimensions();
...@@ -2644,6 +2643,9 @@ void ContextVk::updateViewport(FramebufferVk *framebufferVk, ...@@ -2644,6 +2643,9 @@ void ContextVk::updateViewport(FramebufferVk *framebufferVk,
RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height, RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height,
correctedRect, &rotatedRect); correctedRect, &rotatedRect);
bool invertViewport =
isViewportFlipEnabledForDrawFBO() && getFeatures().supportsNegativeViewport.enabled;
VkViewport vkViewport; VkViewport vkViewport;
gl_vk::GetViewport( gl_vk::GetViewport(
rotatedRect, nearPlane, farPlane, invertViewport, rotatedRect, nearPlane, farPlane, invertViewport,
...@@ -2801,7 +2803,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -2801,7 +2803,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
{ {
FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer()); FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(), updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane(), isViewportFlipEnabledForDrawFBO()); glState.getFarPlane());
// Update the scissor, which will be constrained to the viewport // Update the scissor, which will be constrained to the viewport
updateScissor(glState); updateScissor(glState);
break; break;
...@@ -2984,7 +2986,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -2984,7 +2986,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits(); SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits); updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(), updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane(), isViewportFlipEnabledForDrawFBO()); glState.getFarPlane());
updateColorMasks(glState.getBlendStateExt()); updateColorMasks(glState.getBlendStateExt());
updateRasterizationSamples(mDrawFramebuffer->getSamples()); updateRasterizationSamples(mDrawFramebuffer->getSamples());
...@@ -3097,8 +3099,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -3097,8 +3099,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_CONTROL: case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
updateViewport(vk::GetImpl(glState.getDrawFramebuffer()), updateViewport(vk::GetImpl(glState.getDrawFramebuffer()),
glState.getViewport(), glState.getNearPlane(), glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane(), glState.getFarPlane());
isViewportFlipEnabledForDrawFBO());
// Since we are flipping the y coordinate, update front face state // Since we are flipping the y coordinate, update front face state
mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition, mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
glState.getRasterizerState(), glState.getRasterizerState(),
...@@ -3258,7 +3259,8 @@ void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageB ...@@ -3258,7 +3259,8 @@ void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageB
SurfaceRotation rotationAndFlip = mCurrentRotationDrawFramebuffer; SurfaceRotation rotationAndFlip = mCurrentRotationDrawFramebuffer;
ASSERT(ToUnderlying(rotationAndFlip) < ToUnderlying(SurfaceRotation::FlippedIdentity)); ASSERT(ToUnderlying(rotationAndFlip) < ToUnderlying(SurfaceRotation::FlippedIdentity));
bool yFlipped = bool yFlipped =
isViewportFlipEnabledForDrawFBO() && usageBits.test(sh::vk::SpecConstUsage::YFlip); isViewportFlipEnabledForDrawFBO() && (usageBits.test(sh::vk::SpecConstUsage::YFlip) ||
!getFeatures().supportsNegativeViewport.enabled);
// usageBits are only set when specialization constants are used. With gl_Position pre-rotation // usageBits are only set when specialization constants are used. With gl_Position pre-rotation
// handled by the SPIR-V transformer, we need to have this information even when the driver // handled by the SPIR-V transformer, we need to have this information even when the driver
......
...@@ -737,8 +737,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -737,8 +737,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
void updateViewport(FramebufferVk *framebufferVk, void updateViewport(FramebufferVk *framebufferVk,
const gl::Rectangle &viewport, const gl::Rectangle &viewport,
float nearPlane, float nearPlane,
float farPlane, float farPlane);
bool invertViewport);
void updateDepthRange(float nearPlane, float farPlane); void updateDepthRange(float nearPlane, float farPlane);
void updateFlipViewportDrawFramebuffer(const gl::State &glState); void updateFlipViewportDrawFramebuffer(const gl::State &glState);
void updateFlipViewportReadFramebuffer(const gl::State &glState); void updateFlipViewportReadFramebuffer(const gl::State &glState);
......
...@@ -33,8 +33,10 @@ bool ValidateTransformedSpirV(ContextVk *contextVk, ...@@ -33,8 +33,10 @@ bool ValidateTransformedSpirV(ContextVk *contextVk,
for (gl::ShaderType shaderType : linkedShaderStages) for (gl::ShaderType shaderType : linkedShaderStages)
{ {
GlslangSpirvOptions options; GlslangSpirvOptions options;
options.shaderType = shaderType; options.shaderType = shaderType;
options.preRotation = SurfaceRotation::FlippedRotated90Degrees; options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
options.negativeViewportSupported =
contextVk->getFeatures().supportsNegativeViewport.enabled;
options.transformPositionToVulkanClipSpace = true; options.transformPositionToVulkanClipSpace = true;
options.removeDebugInfo = true; options.removeDebugInfo = true;
options.isTransformFeedbackStage = shaderType == lastPreFragmentStage; options.isTransformFeedbackStage = shaderType == lastPreFragmentStage;
...@@ -135,8 +137,9 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk, ...@@ -135,8 +137,9 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.shaderType = shaderType; options.shaderType = shaderType;
options.removeEarlyFragmentTestsOptimization = options.removeEarlyFragmentTestsOptimization =
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization; shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers(); options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = isLastPreFragmentStage; options.isTransformFeedbackStage = isLastPreFragmentStage;
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
if (isLastPreFragmentStage) if (isLastPreFragmentStage)
{ {
......
...@@ -2010,6 +2010,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ...@@ -2010,6 +2010,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
bool isSwiftShader = bool isSwiftShader =
IsSwiftshader(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID); IsSwiftshader(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID);
bool supportsNegativeViewport =
ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, deviceExtensionNames) ||
mPhysicalDeviceProperties.apiVersion >= VK_API_VERSION_1_1;
if (mLineRasterizationFeatures.bresenhamLines == VK_TRUE) if (mLineRasterizationFeatures.bresenhamLines == VK_TRUE)
{ {
ASSERT(mLineRasterizationFeatures.sType == ASSERT(mLineRasterizationFeatures.sType ==
...@@ -2196,7 +2200,8 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ...@@ -2196,7 +2200,8 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames)); ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames));
// Android pre-rotation support can be disabled. // Android pre-rotation support can be disabled.
ANGLE_FEATURE_CONDITION(&mFeatures, enablePreRotateSurfaces, IsAndroid()); ANGLE_FEATURE_CONDITION(&mFeatures, enablePreRotateSurfaces,
IsAndroid() && supportsNegativeViewport);
// Currently disabled by default: http://anglebug.com/3078 // Currently disabled by default: http://anglebug.com/3078
ANGLE_FEATURE_CONDITION( ANGLE_FEATURE_CONDITION(
...@@ -2278,6 +2283,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ...@@ -2278,6 +2283,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
// required. // required.
ANGLE_FEATURE_CONDITION(&mFeatures, emulateR32fImageAtomicExchange, true); ANGLE_FEATURE_CONDITION(&mFeatures, emulateR32fImageAtomicExchange, true);
// Negative viewports are exposed in the Maintenance1 extension and in core Vulkan 1.1+.
ANGLE_FEATURE_CONDITION(&mFeatures, supportsNegativeViewport, supportsNegativeViewport);
angle::PlatformMethods *platform = ANGLEPlatformCurrent(); angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesVk(platform, &mFeatures); platform->overrideFeaturesVk(platform, &mFeatures);
......
...@@ -1212,13 +1212,15 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND( ...@@ -1212,13 +1212,15 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
WithMetalForcedBufferGPUStorage(ES3_METAL()), WithMetalForcedBufferGPUStorage(ES3_METAL()),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(), WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false, /* hasBarrier */ false,
/* cheapRenderPass */ false)); /* cheapRenderPass */ false),
WithNoVulkanViewportFlip(ES2_VULKAN()));
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND( ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
TriangleFanDrawTest, TriangleFanDrawTest,
WithMetalForcedBufferGPUStorage(ES3_METAL()), WithMetalForcedBufferGPUStorage(ES3_METAL()),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(), WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false, /* hasBarrier */ false,
/* cheapRenderPass */ false)); /* cheapRenderPass */ false),
WithNoVulkanViewportFlip(ES2_VULKAN()));
} // namespace } // namespace
...@@ -254,6 +254,15 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) ...@@ -254,6 +254,15 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
stream << "_ForceMetalBufferGPUStorage"; stream << "_ForceMetalBufferGPUStorage";
} }
if (pp.eglParameters.supportsVulkanViewportFlip == EGL_TRUE)
{
stream << "_VulkanViewportFlip";
}
else if (pp.eglParameters.supportsVulkanViewportFlip == EGL_FALSE)
{
stream << "_NoVulkanViewportFlip";
}
return stream; return stream;
} }
......
...@@ -281,6 +281,13 @@ inline PlatformParameters WithAsyncCommandQueueFeatureVulkan(const PlatformParam ...@@ -281,6 +281,13 @@ inline PlatformParameters WithAsyncCommandQueueFeatureVulkan(const PlatformParam
withAsyncCommandQueue.eglParameters.asyncCommandQueueFeatureVulkan = EGL_TRUE; withAsyncCommandQueue.eglParameters.asyncCommandQueueFeatureVulkan = EGL_TRUE;
return withAsyncCommandQueue; return withAsyncCommandQueue;
} }
inline PlatformParameters WithNoVulkanViewportFlip(const PlatformParameters &params)
{
PlatformParameters withoutVulkanViewportFlip = params;
withoutVulkanViewportFlip.eglParameters.supportsVulkanViewportFlip = EGL_FALSE;
return withoutVulkanViewportFlip;
}
} // namespace angle } // namespace angle
#endif // ANGLE_TEST_CONFIGS_H_ #endif // ANGLE_TEST_CONFIGS_H_
...@@ -564,6 +564,7 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters ...@@ -564,6 +564,7 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters
switch (param.getRenderer()) switch (param.getRenderer())
{ {
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
return true;
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
// Swiftshader's vulkan frontend doesn't build on Android. // Swiftshader's vulkan frontend doesn't build on Android.
if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE) if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
...@@ -574,6 +575,10 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters ...@@ -574,6 +575,10 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters
{ {
return false; return false;
} }
if (param.eglParameters.supportsVulkanViewportFlip == EGL_FALSE)
{
return false;
}
return true; return true;
default: default:
return false; return false;
......
...@@ -64,7 +64,7 @@ struct EGLPlatformParameters ...@@ -64,7 +64,7 @@ struct EGLPlatformParameters
shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods, shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods,
robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan, robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan,
hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl, hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl,
forceBufferGPUStorageFeatureMtl); forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip);
} }
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
...@@ -85,6 +85,7 @@ struct EGLPlatformParameters ...@@ -85,6 +85,7 @@ struct EGLPlatformParameters
EGLint hasExplicitMemBarrierFeatureMtl = EGL_DONT_CARE; EGLint hasExplicitMemBarrierFeatureMtl = EGL_DONT_CARE;
EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE; EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE;
EGLint forceBufferGPUStorageFeatureMtl = EGL_DONT_CARE; EGLint forceBufferGPUStorageFeatureMtl = EGL_DONT_CARE;
EGLint supportsVulkanViewportFlip = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr; angle::PlatformMethods *platformMethods = nullptr;
}; };
......
...@@ -206,6 +206,15 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, ...@@ -206,6 +206,15 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
disabledFeatureOverrides.push_back("gen_multiple_mips_per_pass"); disabledFeatureOverrides.push_back("gen_multiple_mips_per_pass");
} }
if (params.supportsVulkanViewportFlip == EGL_TRUE)
{
enabledFeatureOverrides.push_back("supportsViewportFlip");
}
else if (params.supportsVulkanViewportFlip == EGL_FALSE)
{
disabledFeatureOverrides.push_back("supportsViewportFlip");
}
switch (params.emulatedPrerotation) switch (params.emulatedPrerotation)
{ {
case 90: case 90:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment