mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
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/+/2665892 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Ian Elliott <ianelliott@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
@@ -467,6 +467,10 @@ struct FeaturesVk : FeatureSetBase
|
||||
"emulateR32fImageAtomicExchange", FeatureCategory::VulkanWorkarounds,
|
||||
"Emulate r32f images with r32ui to support imageAtomicExchange.", &members,
|
||||
"http://anglebug.com/5535"};
|
||||
|
||||
Feature supportsNegativeViewport = {
|
||||
"supportsNegativeViewport", FeatureCategory::VulkanFeatures,
|
||||
"The driver supports inverting the viewport with a negative height.", &members};
|
||||
};
|
||||
|
||||
inline FeaturesVk::FeaturesVk() = default;
|
||||
|
||||
@@ -1807,12 +1807,28 @@ void SpirvTransformer::preRotateXY(spirv::IdRef xId,
|
||||
switch (mOptions.preRotation)
|
||||
{
|
||||
case SurfaceRotation::Identity:
|
||||
case SurfaceRotation::FlippedIdentity:
|
||||
// [ 1 0] [x]
|
||||
// [ 0 1] * [y]
|
||||
*rotatedXIdOut = xId;
|
||||
*rotatedYIdOut = yId;
|
||||
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::FlippedRotated90Degrees:
|
||||
// [ 0 1] [x]
|
||||
|
||||
@@ -60,6 +60,7 @@ struct GlslangSpirvOptions
|
||||
{
|
||||
gl::ShaderType shaderType = gl::ShaderType::InvalidEnum;
|
||||
SurfaceRotation preRotation = SurfaceRotation::Identity;
|
||||
bool negativeViewportSupported = false;
|
||||
bool transformPositionToVulkanClipSpace = false;
|
||||
bool removeEarlyFragmentTestsOptimization = false;
|
||||
bool removeDebugInfo = false;
|
||||
|
||||
@@ -2634,8 +2634,7 @@ gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) con
|
||||
void ContextVk::updateViewport(FramebufferVk *framebufferVk,
|
||||
const gl::Rectangle &viewport,
|
||||
float nearPlane,
|
||||
float farPlane,
|
||||
bool invertViewport)
|
||||
float farPlane)
|
||||
{
|
||||
|
||||
gl::Box fbDimensions = framebufferVk->getState().getDimensions();
|
||||
@@ -2644,6 +2643,9 @@ void ContextVk::updateViewport(FramebufferVk *framebufferVk,
|
||||
RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height,
|
||||
correctedRect, &rotatedRect);
|
||||
|
||||
bool invertViewport =
|
||||
isViewportFlipEnabledForDrawFBO() && getFeatures().supportsNegativeViewport.enabled;
|
||||
|
||||
VkViewport vkViewport;
|
||||
gl_vk::GetViewport(
|
||||
rotatedRect, nearPlane, farPlane, invertViewport,
|
||||
@@ -2801,7 +2803,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
||||
{
|
||||
FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
|
||||
updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
|
||||
glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
|
||||
glState.getFarPlane());
|
||||
// Update the scissor, which will be constrained to the viewport
|
||||
updateScissor(glState);
|
||||
break;
|
||||
@@ -2984,7 +2986,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
||||
SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
|
||||
updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
|
||||
updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
|
||||
glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
|
||||
glState.getFarPlane());
|
||||
updateColorMasks(glState.getBlendStateExt());
|
||||
updateRasterizationSamples(mDrawFramebuffer->getSamples());
|
||||
|
||||
@@ -3097,8 +3099,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
||||
case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
|
||||
updateViewport(vk::GetImpl(glState.getDrawFramebuffer()),
|
||||
glState.getViewport(), glState.getNearPlane(),
|
||||
glState.getFarPlane(),
|
||||
isViewportFlipEnabledForDrawFBO());
|
||||
glState.getFarPlane());
|
||||
// Since we are flipping the y coordinate, update front face state
|
||||
mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
|
||||
glState.getRasterizerState(),
|
||||
@@ -3258,7 +3259,8 @@ void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageB
|
||||
SurfaceRotation rotationAndFlip = mCurrentRotationDrawFramebuffer;
|
||||
ASSERT(ToUnderlying(rotationAndFlip) < ToUnderlying(SurfaceRotation::FlippedIdentity));
|
||||
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
|
||||
// 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
|
||||
void updateViewport(FramebufferVk *framebufferVk,
|
||||
const gl::Rectangle &viewport,
|
||||
float nearPlane,
|
||||
float farPlane,
|
||||
bool invertViewport);
|
||||
float farPlane);
|
||||
void updateDepthRange(float nearPlane, float farPlane);
|
||||
void updateFlipViewportDrawFramebuffer(const gl::State &glState);
|
||||
void updateFlipViewportReadFramebuffer(const gl::State &glState);
|
||||
|
||||
@@ -33,8 +33,10 @@ bool ValidateTransformedSpirV(ContextVk *contextVk,
|
||||
for (gl::ShaderType shaderType : linkedShaderStages)
|
||||
{
|
||||
GlslangSpirvOptions options;
|
||||
options.shaderType = shaderType;
|
||||
options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
|
||||
options.shaderType = shaderType;
|
||||
options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
|
||||
options.negativeViewportSupported =
|
||||
contextVk->getFeatures().supportsNegativeViewport.enabled;
|
||||
options.transformPositionToVulkanClipSpace = true;
|
||||
options.removeDebugInfo = true;
|
||||
options.isTransformFeedbackStage = shaderType == lastPreFragmentStage;
|
||||
@@ -135,8 +137,9 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
|
||||
options.shaderType = shaderType;
|
||||
options.removeEarlyFragmentTestsOptimization =
|
||||
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
|
||||
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
|
||||
options.isTransformFeedbackStage = isLastPreFragmentStage;
|
||||
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
|
||||
options.isTransformFeedbackStage = isLastPreFragmentStage;
|
||||
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
|
||||
|
||||
if (isLastPreFragmentStage)
|
||||
{
|
||||
|
||||
@@ -2010,6 +2010,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
bool isSwiftShader =
|
||||
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)
|
||||
{
|
||||
ASSERT(mLineRasterizationFeatures.sType ==
|
||||
@@ -2196,7 +2200,8 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames));
|
||||
|
||||
// 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
|
||||
ANGLE_FEATURE_CONDITION(
|
||||
@@ -2278,6 +2283,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
// required.
|
||||
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();
|
||||
platform->overrideFeaturesVk(platform, &mFeatures);
|
||||
|
||||
|
||||
@@ -1212,13 +1212,15 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
|
||||
WithMetalForcedBufferGPUStorage(ES3_METAL()),
|
||||
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
|
||||
/* hasBarrier */ false,
|
||||
/* cheapRenderPass */ false));
|
||||
/* cheapRenderPass */ false),
|
||||
WithNoVulkanViewportFlip(ES2_VULKAN()));
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
|
||||
TriangleFanDrawTest,
|
||||
WithMetalForcedBufferGPUStorage(ES3_METAL()),
|
||||
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
|
||||
/* hasBarrier */ false,
|
||||
/* cheapRenderPass */ false));
|
||||
/* cheapRenderPass */ false),
|
||||
WithNoVulkanViewportFlip(ES2_VULKAN()));
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -254,6 +254,15 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
|
||||
stream << "_ForceMetalBufferGPUStorage";
|
||||
}
|
||||
|
||||
if (pp.eglParameters.supportsVulkanViewportFlip == EGL_TRUE)
|
||||
{
|
||||
stream << "_VulkanViewportFlip";
|
||||
}
|
||||
else if (pp.eglParameters.supportsVulkanViewportFlip == EGL_FALSE)
|
||||
{
|
||||
stream << "_NoVulkanViewportFlip";
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,13 @@ inline PlatformParameters WithAsyncCommandQueueFeatureVulkan(const PlatformParam
|
||||
withAsyncCommandQueue.eglParameters.asyncCommandQueueFeatureVulkan = EGL_TRUE;
|
||||
return withAsyncCommandQueue;
|
||||
}
|
||||
|
||||
inline PlatformParameters WithNoVulkanViewportFlip(const PlatformParameters ¶ms)
|
||||
{
|
||||
PlatformParameters withoutVulkanViewportFlip = params;
|
||||
withoutVulkanViewportFlip.eglParameters.supportsVulkanViewportFlip = EGL_FALSE;
|
||||
return withoutVulkanViewportFlip;
|
||||
}
|
||||
} // namespace angle
|
||||
|
||||
#endif // ANGLE_TEST_CONFIGS_H_
|
||||
|
||||
@@ -564,6 +564,7 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters
|
||||
switch (param.getRenderer())
|
||||
{
|
||||
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
|
||||
return true;
|
||||
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
|
||||
// Swiftshader's vulkan frontend doesn't build on Android.
|
||||
if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
|
||||
@@ -574,6 +575,10 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (param.eglParameters.supportsVulkanViewportFlip == EGL_FALSE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -64,7 +64,7 @@ struct EGLPlatformParameters
|
||||
shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods,
|
||||
robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan,
|
||||
hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl,
|
||||
forceBufferGPUStorageFeatureMtl);
|
||||
forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip);
|
||||
}
|
||||
|
||||
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
|
||||
@@ -85,6 +85,7 @@ struct EGLPlatformParameters
|
||||
EGLint hasExplicitMemBarrierFeatureMtl = EGL_DONT_CARE;
|
||||
EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE;
|
||||
EGLint forceBufferGPUStorageFeatureMtl = EGL_DONT_CARE;
|
||||
EGLint supportsVulkanViewportFlip = EGL_DONT_CARE;
|
||||
angle::PlatformMethods *platformMethods = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -206,6 +206,15 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
|
||||
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)
|
||||
{
|
||||
case 90:
|
||||
|
||||
Reference in New Issue
Block a user