Commit 626a7280 by Tim Van Patten Committed by Commit Bot

Vulkan: Implement framebuffers without attachments

It is possible to render to a framebuffer object that has no attachments. However, the rasterization of primitives is always based on the area and characteristics of the bound framebuffer. These characteristics (size, number of samples, etc.) would normally be defined by the attached images. If no images are attached, these characteristics are defined by their default values. Bug: angleproject:3579 Test: dEQP-GLES31.functional.fbo.*no_attachments* Test: dEQP-GLES31.functional.state_query.framebuffer_default.* Change-Id: I9580b924ac810db573cd8df96273fbb01bbb1f73 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1690688Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Commit-Queue: Tim Van Patten <timvp@google.com>
parent ad77f55e
......@@ -609,8 +609,12 @@ Box FramebufferState::getDimensions() const
Extents FramebufferState::getExtents() const
{
ASSERT(attachmentsHaveSameDimensions());
ASSERT(getFirstNonNullAttachment() != nullptr);
return getFirstNonNullAttachment()->getSize();
const FramebufferAttachment *first = getFirstNonNullAttachment();
if (first)
{
return first->getSize();
}
return Extents(getDefaultWidth(), getDefaultHeight(), 0);
}
Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
......
......@@ -1414,7 +1414,41 @@ void ContextVk::updateViewport(FramebufferVk *framebufferVk,
bool invertViewport)
{
VkViewport vkViewport;
gl_vk::GetViewport(viewport, nearPlane, farPlane, invertViewport,
const gl::Caps &caps = getCaps();
const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
const int viewportBoundsRangeLow = static_cast<int>(limitsVk.viewportBoundsRange[0]);
const int viewportBoundsRangeHigh = static_cast<int>(limitsVk.viewportBoundsRange[1]);
// Clamp the viewport values to what Vulkan specifies
// width must be greater than 0.0 and less than or equal to
// VkPhysicalDeviceLimits::maxViewportDimensions[0]
int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
correctedWidth = std::max<int>(correctedWidth, 0);
// height must be greater than 0.0 and less than or equal to
// VkPhysicalDeviceLimits::maxViewportDimensions[1]
int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
correctedHeight = std::max<int>(correctedHeight, 0);
// x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive
int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh);
correctedX = std::max<int>(correctedX, viewportBoundsRangeLow);
int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh);
correctedY = std::max<int>(correctedY, viewportBoundsRangeLow);
// x + width must be less than or equal to viewportBoundsRange[1]
if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
{
correctedWidth = viewportBoundsRangeHigh - correctedX;
}
// y + height must be less than or equal to viewportBoundsRange[1]
if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
{
correctedHeight = viewportBoundsRangeHigh - correctedY;
}
gl::Rectangle correctedRect =
gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
gl_vk::GetViewport(correctedRect, nearPlane, farPlane, invertViewport,
framebufferVk->getState().getDimensions().height, &vkViewport);
mGraphicsPipelineDesc->updateViewport(&mGraphicsPipelineTransition, vkViewport);
invalidateDriverUniforms();
......
......@@ -309,6 +309,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
Serial generateTextureSerial() { return mTextureSerialFactory.generate(); }
const vk::TextureDescriptorDesc &getActiveTexturesDesc() const { return mActiveTexturesDesc; }
void updateScissor(const gl::State &glState);
private:
// Dirty bits.
enum DirtyBitType : size_t
......@@ -365,7 +367,6 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
float farPlane,
bool invertViewport);
void updateDepthRange(float nearPlane, float farPlane);
void updateScissor(const gl::State &glState);
void updateFlipViewportDrawFramebuffer(const gl::State &glState);
void updateFlipViewportReadFramebuffer(const gl::State &glState);
......
......@@ -1097,11 +1097,14 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
ANGLE_TRY(mRenderTargetCache.getColors()[colorIndexGL]->flushStagedUpdates(
contextVk));
}
break;
}
}
}
// The FBOs new attachment may have changed the renderable area
const gl::State &glState = context->getState();
contextVk->updateScissor(glState);
mActiveColorComponents = gl_vk::GetColorComponentFlags(
mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
......@@ -1197,6 +1200,14 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe
attachmentsSize = depthStencilRenderTarget->getExtents();
}
if (attachmentsSize.empty())
{
// No attachments, so use the default values.
attachmentsSize.height = mState.getDefaultHeight();
attachmentsSize.width = mState.getDefaultWidth();
attachmentsSize.depth = 0;
}
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
......@@ -1515,13 +1526,14 @@ gl::Extents FramebufferVk::getReadImageExtents() const
gl::Rectangle FramebufferVk::getCompleteRenderArea() const
{
return gl::Rectangle(0, 0, mState.getDimensions().width, mState.getDimensions().height);
const gl::Box &dimensions = mState.getDimensions();
return gl::Rectangle(0, 0, dimensions.width, dimensions.height);
}
gl::Rectangle FramebufferVk::getScissoredRenderArea(ContextVk *contextVk) const
{
const gl::Rectangle renderArea(0, 0, mState.getDimensions().width,
mState.getDimensions().height);
const gl::Box &dimensions = mState.getDimensions();
const gl::Rectangle renderArea(0, 0, dimensions.width, dimensions.height);
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
return ClipRectToScissor(contextVk->getState(), renderArea, invertViewport);
......
......@@ -203,6 +203,7 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Compute] = maxUniformComponents;
mNativeCaps.maxUniformLocations = maxUniformVectors;
// Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
// uniforms.
......@@ -384,6 +385,7 @@ void RendererVk::ensureCapsInitialized() const
limitsVk.framebufferStencilSampleCounts;
mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts);
mNativeCaps.maxFramebufferSamples = mNativeCaps.maxSamples;
mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
......
......@@ -657,8 +657,8 @@
// Block name matching failure:
3459 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.mismatch_with_and_without_instance_name = FAIL
// Explicit uniform locations:
3597 VULKAN : dEQP-GLES31.functional.uniform_location.* = FAIL
// Shader support for arrays-of-arrays
3604 VULKAN : dEQP-GLES31.functional.uniform_location.nested_array.* = SKIP
// Indirect draw:
3564 VULKAN : dEQP-GLES31.functional.draw_indirect.* = SKIP
......@@ -676,11 +676,8 @@
3563 VULKAN : dEQP-GLES31.functional.synchronization.*.image* = FAIL
3563 VULKAN : dEQP-GLES31.functional.compute.*image* = FAIL
// Framebuffer parameters (FRAMEBUFFER_DEFAULT_SAMPLES):
3520 VULKAN : dEQP-GLES31.functional.state_query.framebuffer_default.framebuffer_default_samples_get_framebuffer_parameteriv = FAIL
// Framebuffer without attachments:
3579 VULKAN : dEQP-GLES31.functional.fbo.no_attachments.* = SKIP
3579 ANDROID VULKAN : dEQP-GLES31.functional.fbo.no_attachments.* = SKIP
// Separate shader objects:
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.*separable_* = FAIL
......
......@@ -92,7 +92,8 @@
3564 VULKAN : KHR-GLES31.core.draw_indirect.* = SKIP
// Explicit uniform locations:
3597 VULKAN : KHR-GLES31.core.explicit_uniform_location.* = SKIP
3604 VULKAN : KHR-GLES31.core.explicit_uniform_location.uniform-loc-arrays-of-arrays = SKIP
3520 VULKAN : KHR-GLES31.core.explicit_uniform_location.* = SKIP
3520 VULKAN : KHR-GLES31.core.program_interface_query.* = SKIP
......
......@@ -679,6 +679,9 @@ class FramebufferTest_ES31 : public ANGLETest
// FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is incomplete.
TEST_P(FramebufferTest_ES31, IncompleteMissingAttachmentDefaultParam)
{
// anglebug.com/3565
ANGLE_SKIP_TEST_IF(IsVulkan());
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
......@@ -707,6 +710,9 @@ TEST_P(FramebufferTest_ES31, IncompleteMissingAttachmentDefaultParam)
// Test that the sample count of a mix of texture and renderbuffer should be same.
TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountMix)
{
// anglebug.com/3565
ANGLE_SKIP_TEST_IF(IsVulkan());
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
......@@ -730,6 +736,9 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountMix)
// Test that the sample count of texture attachments should be same.
TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountTex)
{
// anglebug.com/3565
ANGLE_SKIP_TEST_IF(IsVulkan());
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
......@@ -752,6 +761,9 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountTex)
// TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsMix)
{
// anglebug.com/3565
ANGLE_SKIP_TEST_IF(IsVulkan());
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
......@@ -775,6 +787,9 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsMix)
// Test that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS is the same for all attached textures.
TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsTex)
{
// anglebug.com/3565
ANGLE_SKIP_TEST_IF(IsVulkan());
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
......@@ -800,6 +815,8 @@ TEST_P(FramebufferTest_ES31, RenderingLimitToDefaultFBOSizeWithNoAttachments)
{
// anglebug.com/2253
ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsDesktopOpenGL());
// Occlusion query reports fragments outside the render area are still rendered
ANGLE_SKIP_TEST_IF(IsAndroid() || (IsWindows() && (IsIntel() || IsAMD())));
constexpr char kVS1[] = R"(#version 310 es
in layout(location = 0) highp vec2 a_position;
......@@ -909,7 +926,11 @@ void main()
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(FramebufferTest_ES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(FramebufferTest_ES31,
ES31_D3D11(),
ES31_OPENGL(),
ES31_OPENGLES(),
ES31_VULKAN());
class AddDummyTextureNoRenderTargetTest : public ANGLETest
{
......
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