Commit a76b6836 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support MSRTT depth/stencil resolve

VK_KHR_depth_stencil_resolve is used by this change to resolve depth/stencil multisampled-render-to-texture renderbuffers. This extension is not widely supported yet. If it's not present, the depth/stencil resolve operation is silently ignored and the renderbuffer acts as a normal multisampled one. This is not correct, but our primary user (Chrome), and most applications don't care for the resolved depth/stencil data. In fact, it's recommended for the depth/stencil attachment to be invalidated after rendering. Exposing EXT_multisampled_render_to_texture even in the absence of depth/stencil resolve allows the majority of the applications to still take advantage of MSRTT color attachments. Bug: angleproject:4836 Change-Id: I6ba4187344a0c9330d2c77bdc5e2c6fc5483c299 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2417645 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent f0b02054
...@@ -73,6 +73,10 @@ struct FeaturesVk : FeatureSetBase ...@@ -73,6 +73,10 @@ struct FeaturesVk : FeatureSetBase
"vertex shader that reads from it is ineffective", "vertex shader that reads from it is ineffective",
&members, "http://anglebug.com/3016"}; &members, "http://anglebug.com/3016"};
Feature supportsRenderpass2 = {"supports_renderpass2", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_KHR_create_renderpass2 extension",
&members};
// Whether the VkDevice supports the VK_KHR_incremental_present extension, on which the // Whether the VkDevice supports the VK_KHR_incremental_present extension, on which the
// EGL_KHR_swap_buffers_with_damage extension can be layered. // EGL_KHR_swap_buffers_with_damage extension can be layered.
Feature supportsIncrementalPresent = { Feature supportsIncrementalPresent = {
...@@ -184,6 +188,15 @@ struct FeaturesVk : FeatureSetBase ...@@ -184,6 +188,15 @@ struct FeaturesVk : FeatureSetBase
"VkDevice supports the VK_EXT_index_type_uint8 extension", "VkDevice supports the VK_EXT_index_type_uint8 extension",
&members, "http://anglebug.com/4405"}; &members, "http://anglebug.com/4405"};
// Whether the VkDevice supports the VK_KHR_depth_stencil_resolve extension with the
// independentResolveNone feature.
// http://anglebug.com/4836
Feature supportsDepthStencilResolve = {"supports_depth_stencil_resolve",
FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_KHR_depth_stencil_resolve "
"extension with the independentResolveNone feature",
&members, "http://anglebug.com/4836"};
// VK_PRESENT_MODE_FIFO_KHR causes random timeouts on Linux Intel. http://anglebug.com/3153 // VK_PRESENT_MODE_FIFO_KHR causes random timeouts on Linux Intel. http://anglebug.com/3153
Feature disableFifoPresentMode = { Feature disableFifoPresentMode = {
"disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds, "disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds,
......
...@@ -74,6 +74,9 @@ extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR ...@@ -74,6 +74,9 @@ extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR;
extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR;
// VK_KHR_create_renderpass2
extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR;
# if defined(ANGLE_PLATFORM_FUCHSIA) # if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface // VK_FUCHSIA_imagepipe_surface
extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA;
......
...@@ -1600,6 +1600,16 @@ void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk) ...@@ -1600,6 +1600,16 @@ void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk)
{ {
mCurrentFramebufferDesc.updateDepthStencil(vk::kInvalidImageViewSubresourceSerial); mCurrentFramebufferDesc.updateDepthStencil(vk::kInvalidImageViewSubresourceSerial);
} }
if (depthStencilRT != nullptr && depthStencilRT->hasResolveAttachment())
{
mCurrentFramebufferDesc.updateDepthStencilResolve(
depthStencilRT->getResolveSubresourceSerial());
}
else
{
mCurrentFramebufferDesc.updateDepthStencilResolve(vk::kInvalidImageViewSubresourceSerial);
}
} }
angle::Result FramebufferVk::syncState(const gl::Context *context, angle::Result FramebufferVk::syncState(const gl::Context *context,
...@@ -1793,6 +1803,16 @@ void FramebufferVk::updateRenderPassDesc() ...@@ -1793,6 +1803,16 @@ void FramebufferVk::updateRenderPassDesc()
mRenderPassDesc.packDepthStencilAttachment( mRenderPassDesc.packDepthStencilAttachment(
depthStencilRenderTarget->getImageForRenderPass().getFormat().intendedFormatID, depthStencilRenderTarget->getImageForRenderPass().getFormat().intendedFormatID,
dsAccess); dsAccess);
// Add the resolve attachment, if any.
if (depthStencilRenderTarget->hasResolveAttachment())
{
const vk::Format &format = depthStencilRenderTarget->getImageFormat();
bool hasDepth = format.intendedFormat().depthBits > 0;
bool hasStencil = format.intendedFormat().stencilBits > 0;
mRenderPassDesc.packDepthStencilResolveAttachment(hasDepth, hasStencil);
}
} }
} }
...@@ -1894,6 +1914,17 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, ...@@ -1894,6 +1914,17 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
} }
} }
// Depth/stencil resolve attachment.
if (depthStencilRenderTarget && depthStencilRenderTarget->hasResolveAttachment())
{
const vk::ImageView *imageView = nullptr;
ANGLE_TRY(depthStencilRenderTarget->getResolveImageView(contextVk, &imageView));
attachments.push_back(imageView->getHandle());
ASSERT(!attachmentsSize.empty());
}
if (attachmentsSize.empty()) if (attachmentsSize.empty())
{ {
// No attachments, so use the default values. // No attachments, so use the default values.
...@@ -2265,7 +2296,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2265,7 +2296,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// depth stencil attachment always immediately follow color attachment // depth stencil attachment always immediately follows color attachment
depthStencilAttachmentIndex = colorIndexVk; depthStencilAttachmentIndex = colorIndexVk;
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
...@@ -2286,8 +2317,14 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2286,8 +2317,14 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (depthStencilRenderTarget->isImageTransient()) if (depthStencilRenderTarget->isImageTransient())
{ {
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // TODO(syoussefi): currently, depth/stencil unresolve is not implemented. Until then,
stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // don't change storeOp to DONT_CARE, unless the attachment is entirely transient (i.e.
// depth textures from EXT_multisampled_render_to_texture2. http://anglebug.com/4836
if (depthStencilRenderTarget->isEntirelyTransient())
{
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
} }
vk::ImageLayout dsLayout = isReadOnlyDepthMode() ? vk::ImageLayout::DepthStencilReadOnly vk::ImageLayout dsLayout = isReadOnlyDepthMode() ? vk::ImageLayout::DepthStencilReadOnly
......
...@@ -115,7 +115,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -115,7 +115,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void restoreEntireContent() { mContentDefined = true; } void restoreEntireContent() { mContentDefined = true; }
// See the description of mTransience for details of how the following two can interact. // See the description of mTransience for details of how the following two can interact.
bool hasResolveAttachment() const { return mResolveImage != nullptr; } bool hasResolveAttachment() const { return mResolveImage != nullptr && !isEntirelyTransient(); }
bool isImageTransient() const { return mTransience != RenderTargetTransience::Default; } bool isImageTransient() const { return mTransience != RenderTargetTransience::Default; }
bool isEntirelyTransient() const bool isEntirelyTransient() const
{ {
......
...@@ -81,11 +81,12 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context, ...@@ -81,11 +81,12 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
const bool isDepthStencilFormat = textureFormat.hasDepthOrStencilBits(); const bool isDepthStencilFormat = textureFormat.hasDepthOrStencilBits();
ASSERT(textureFormat.redBits > 0 || isDepthStencilFormat); ASSERT(textureFormat.redBits > 0 || isDepthStencilFormat);
// TODO(syoussefi): Currently not supported for depth/stencil images. Tests (and Chromium) only // TODO(syoussefi): Currently not supported for depth/stencil images if
// use this for depth/stencil buffers and don't attempt to read from it. This needs to be fixed // VK_KHR_depth_stencil_resolve is not supported. Chromium only uses this for depth/stencil
// and tests added. http://anglebug.com/4836 // buffers and doesn't attempt to read from it. http://anglebug.com/5065
const bool isRenderToTexture = const bool isRenderToTexture =
mode == gl::MultisamplingMode::MultisampledRenderToTexture && !isDepthStencilFormat; mode == gl::MultisamplingMode::MultisampledRenderToTexture &&
(!isDepthStencilFormat || renderer->getFeatures().supportsDepthStencilResolve.enabled);
const VkImageUsageFlags usage = const VkImageUsageFlags usage =
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
......
...@@ -935,6 +935,10 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt ...@@ -935,6 +935,10 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
mShaderFloat16Int8Features.sType = mShaderFloat16Int8Features.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES;
mDepthStencilResolveProperties = {};
mDepthStencilResolveProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
mExternalFenceProperties = {}; mExternalFenceProperties = {};
mExternalFenceProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES; mExternalFenceProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES;
...@@ -1006,6 +1010,12 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt ...@@ -1006,6 +1010,12 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
vk::AddToPNextChain(&deviceFeatures, &mShaderFloat16Int8Features); vk::AddToPNextChain(&deviceFeatures, &mShaderFloat16Int8Features);
} }
// Query depth/stencil resolve properties
if (ExtensionFound(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceProperties, &mDepthStencilResolveProperties);
}
// Query subgroup properties // Query subgroup properties
vk::AddToPNextChain(&deviceProperties, &mSubgroupProperties); vk::AddToPNextChain(&deviceProperties, &mSubgroupProperties);
...@@ -1043,14 +1053,9 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt ...@@ -1043,14 +1053,9 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
mIndexTypeUint8Features.pNext = nullptr; mIndexTypeUint8Features.pNext = nullptr;
mSubgroupProperties.pNext = nullptr; mSubgroupProperties.pNext = nullptr;
mExternalMemoryHostProperties.pNext = nullptr; mExternalMemoryHostProperties.pNext = nullptr;
mLineRasterizationFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr;
mTransformFeedbackFeatures.pNext = nullptr;
mIndexTypeUint8Features.pNext = nullptr;
mSamplerYcbcrConversionFeatures.pNext = nullptr;
mShaderFloat16Int8Features.pNext = nullptr; mShaderFloat16Int8Features.pNext = nullptr;
mDepthStencilResolveProperties.pNext = nullptr;
mSamplerYcbcrConversionFeatures.pNext = nullptr;
} }
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex) angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
...@@ -1169,6 +1174,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1169,6 +1174,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
} }
if (getFeatures().supportsRenderpass2.enabled)
{
enabledDeviceExtensions.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
}
if (getFeatures().supportsIncrementalPresent.enabled) if (getFeatures().supportsIncrementalPresent.enabled)
{ {
enabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
...@@ -1357,6 +1367,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1357,6 +1367,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vk::AddToPNextChain(&createInfo, &mIndexTypeUint8Features); vk::AddToPNextChain(&createInfo, &mIndexTypeUint8Features);
} }
if (getFeatures().supportsDepthStencilResolve.enabled)
{
enabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
}
if (getFeatures().supportsExternalMemoryHost.enabled) if (getFeatures().supportsExternalMemoryHost.enabled)
{ {
enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);
...@@ -1434,6 +1449,10 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1434,6 +1449,10 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
{ {
InitSamplerYcbcrKHRFunctions(mDevice); InitSamplerYcbcrKHRFunctions(mDevice);
} }
if (getFeatures().supportsRenderpass2.enabled)
{
InitRenderPass2KHRFunctions(mDevice);
}
#endif // !defined(ANGLE_SHARED_LIBVULKAN) #endif // !defined(ANGLE_SHARED_LIBVULKAN)
if (getFeatures().forceMaxUniformBufferSize16KB.enabled) if (getFeatures().forceMaxUniformBufferSize16KB.enabled)
...@@ -1712,6 +1731,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev ...@@ -1712,6 +1731,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev
mPhysicalDeviceProperties.deviceID)); mPhysicalDeviceProperties.deviceID));
ANGLE_FEATURE_CONDITION( ANGLE_FEATURE_CONDITION(
&mFeatures, supportsRenderpass2,
ExtensionFound(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, deviceExtensionNames));
ANGLE_FEATURE_CONDITION(
&mFeatures, supportsIncrementalPresent, &mFeatures, supportsIncrementalPresent,
ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames)); ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames));
...@@ -1791,6 +1814,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev ...@@ -1791,6 +1814,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev
ANGLE_FEATURE_CONDITION(&mFeatures, supportsIndexTypeUint8, ANGLE_FEATURE_CONDITION(&mFeatures, supportsIndexTypeUint8,
mIndexTypeUint8Features.indexTypeUint8 == VK_TRUE); mIndexTypeUint8Features.indexTypeUint8 == VK_TRUE);
ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthStencilResolve,
mFeatures.supportsRenderpass2.enabled &&
mDepthStencilResolveProperties.independentResolveNone == VK_TRUE);
ANGLE_FEATURE_CONDITION(&mFeatures, emulateTransformFeedback, ANGLE_FEATURE_CONDITION(&mFeatures, emulateTransformFeedback,
(!mFeatures.supportsTransformFeedbackExtension.enabled && (!mFeatures.supportsTransformFeedbackExtension.enabled &&
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE)); mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE));
......
...@@ -317,6 +317,7 @@ class RendererVk : angle::NonCopyable ...@@ -317,6 +317,7 @@ class RendererVk : angle::NonCopyable
VkPhysicalDeviceSubgroupProperties mSubgroupProperties; VkPhysicalDeviceSubgroupProperties mSubgroupProperties;
VkPhysicalDeviceExternalMemoryHostPropertiesEXT mExternalMemoryHostProperties; VkPhysicalDeviceExternalMemoryHostPropertiesEXT mExternalMemoryHostProperties;
VkPhysicalDeviceShaderFloat16Int8FeaturesKHR mShaderFloat16Int8Features; VkPhysicalDeviceShaderFloat16Int8FeaturesKHR mShaderFloat16Int8Features;
VkPhysicalDeviceDepthStencilResolvePropertiesKHR mDepthStencilResolveProperties;
VkExternalFenceProperties mExternalFenceProperties; VkExternalFenceProperties mExternalFenceProperties;
VkExternalSemaphoreProperties mExternalSemaphoreProperties; VkExternalSemaphoreProperties mExternalSemaphoreProperties;
VkPhysicalDeviceSamplerYcbcrConversionFeatures mSamplerYcbcrConversionFeatures; VkPhysicalDeviceSamplerYcbcrConversionFeatures mSamplerYcbcrConversionFeatures;
......
...@@ -163,9 +163,9 @@ void UnpackAttachmentDesc(VkAttachmentDescription *desc, ...@@ -163,9 +163,9 @@ void UnpackAttachmentDesc(VkAttachmentDescription *desc,
ConvertImageLayoutToVkImageLayout(static_cast<ImageLayout>(ops.finalLayout)); ConvertImageLayoutToVkImageLayout(static_cast<ImageLayout>(ops.finalLayout));
} }
void UnpackResolveAttachmentDesc(VkAttachmentDescription *desc, void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc,
const vk::Format &format, const vk::Format &format,
bool usedAsInputAttachment) bool usedAsInputAttachment)
{ {
// We would only need this flag for duplicated attachments. Apply it conservatively. In // We would only need this flag for duplicated attachments. Apply it conservatively. In
// practice it's unlikely any application would use the same image as multiple resolve // practice it's unlikely any application would use the same image as multiple resolve
...@@ -174,7 +174,7 @@ void UnpackResolveAttachmentDesc(VkAttachmentDescription *desc, ...@@ -174,7 +174,7 @@ void UnpackResolveAttachmentDesc(VkAttachmentDescription *desc,
desc->flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT; desc->flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
desc->format = format.vkImageFormat; desc->format = format.vkImageFormat;
// We don't support depth/stencil resolve attachments currently. // This function is for color resolve attachments.
const angle::Format &angleFormat = format.actualImageFormat(); const angle::Format &angleFormat = format.actualImageFormat();
ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0); ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0);
...@@ -194,6 +194,32 @@ void UnpackResolveAttachmentDesc(VkAttachmentDescription *desc, ...@@ -194,6 +194,32 @@ void UnpackResolveAttachmentDesc(VkAttachmentDescription *desc,
desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
} }
void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc,
const vk::Format &format)
{
// There cannot be simultaneous usages of the depth/stencil resolve image, as depth/stencil
// resolve currently only comes from depth/stencil renderbuffers.
desc->flags = 0;
desc->format = format.vkImageFormat;
// This function is for depth/stencil resolve attachment.
const angle::Format &angleFormat = format.intendedFormat();
ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0);
// Resolve attachments always have a sample count of 1. Currently, invalidate of
// multisampled-render-to-texture depth/stencil renderbuffer is not implemented. Therefore,
// loadOp and storeOp can be fixed to DONT_CARE and STORE respectively.
desc->samples = VK_SAMPLE_COUNT_1_BIT;
desc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->storeOp =
angleFormat.depthBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->stencilStoreOp = angleFormat.stencilBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE
: VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
desc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
void UnpackStencilState(const vk::PackedStencilOpState &packedState, void UnpackStencilState(const vk::PackedStencilOpState &packedState,
uint8_t stencilReference, uint8_t stencilReference,
VkStencilOpState *stateOut) VkStencilOpState *stateOut)
...@@ -241,9 +267,10 @@ void InitializeUnresolveSubpass( ...@@ -241,9 +267,10 @@ void InitializeUnresolveSubpass(
const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassColorAttachmentRefs, const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassColorAttachmentRefs,
const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassResolveAttachmentRefs, const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassResolveAttachmentRefs,
const VkAttachmentReference &depthStencilAttachmentRef, const VkAttachmentReference &depthStencilAttachmentRef,
const VkAttachmentReference2KHR &depthStencilResolveAttachmentRef,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveColorAttachmentRefs, gl::DrawBuffersVector<VkAttachmentReference> *unresolveColorAttachmentRefs,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveInputAttachmentRefs, gl::DrawBuffersVector<VkAttachmentReference> *unresolveInputAttachmentRefs,
gl::DrawBuffersVector<uint32_t> *unresolvePreserveAttachmentRefs, FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs,
VkSubpassDescription *subpassDesc) VkSubpassDescription *subpassDesc)
{ {
for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL) for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
...@@ -346,6 +373,7 @@ void InitializeUnresolveSubpass( ...@@ -346,6 +373,7 @@ void InitializeUnresolveSubpass(
unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} }
// Preserve depth/stencil attachments.
if (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED) if (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED)
{ {
// There's no need to preserve the depth attachment if loadOp=DONT_CARE, but we do for // There's no need to preserve the depth attachment if loadOp=DONT_CARE, but we do for
...@@ -373,17 +401,17 @@ void InitializeUnresolveSubpass( ...@@ -373,17 +401,17 @@ void InitializeUnresolveSubpass(
// There is normally one subpass, and occasionally another for the unresolve operation. // There is normally one subpass, and occasionally another for the unresolve operation.
constexpr size_t kSubpassFastVectorSize = 2; constexpr size_t kSubpassFastVectorSize = 2;
using SubpassList = angle::FastVector<VkSubpassDescription, kSubpassFastVectorSize>; template <typename T>
using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>;
void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc, void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription> &subpassDesc,
std::vector<VkSubpassDependency> *subpassDependencies) std::vector<VkSubpassDependency> *subpassDependencies)
{ {
ASSERT(subpassDesc.size() >= 2); ASSERT(subpassDesc.size() >= 2);
// The unresolve subpass is the first subpass. The application draw subpass is the last // The unresolve subpass is the first subpass. The application draw subpass is the next one.
// subpass. constexpr uint32_t kUnresolveSubpassIndex = 0;
const uint32_t srcSubpass = 0; constexpr uint32_t kDrawSubpassIndex = 1;
const uint32_t dstSubpass = static_cast<uint32_t>(subpassDesc.size() - 1);
// A subpass dependency is needed between the unresolve and draw subpasses. There are two // A subpass dependency is needed between the unresolve and draw subpasses. There are two
// hazards here: // hazards here:
...@@ -419,8 +447,8 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc, ...@@ -419,8 +447,8 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc,
subpassDependencies->emplace_back(); subpassDependencies->emplace_back();
VkSubpassDependency *dependency = &subpassDependencies->back(); VkSubpassDependency *dependency = &subpassDependencies->back();
dependency->srcSubpass = srcSubpass; dependency->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = dstSubpass; dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
...@@ -430,8 +458,8 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc, ...@@ -430,8 +458,8 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc,
subpassDependencies->emplace_back(); subpassDependencies->emplace_back();
dependency = &subpassDependencies->back(); dependency = &subpassDependencies->back();
dependency->srcSubpass = srcSubpass; dependency->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = dstSubpass; dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; dependency->srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
...@@ -439,18 +467,181 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc, ...@@ -439,18 +467,181 @@ void InitializeUnresolveSubpassDependencies(const SubpassList &subpassDesc,
dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
} }
angle::Result InitializeRenderPassFromDesc(vk::Context *context, void ToAttachmentDesciption2(const VkAttachmentDescription &desc,
VkAttachmentDescription2KHR *desc2Out)
{
*desc2Out = {};
desc2Out->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
desc2Out->flags = desc.flags;
desc2Out->format = desc.format;
desc2Out->samples = desc.samples;
desc2Out->loadOp = desc.loadOp;
desc2Out->storeOp = desc.storeOp;
desc2Out->stencilLoadOp = desc.stencilLoadOp;
desc2Out->stencilStoreOp = desc.stencilStoreOp;
desc2Out->initialLayout = desc.initialLayout;
desc2Out->finalLayout = desc.finalLayout;
}
void ToAttachmentReference2(const VkAttachmentReference &ref,
VkImageAspectFlags aspectMask,
VkAttachmentReference2KHR *ref2Out)
{
*ref2Out = {};
ref2Out->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
ref2Out->attachment = ref.attachment;
ref2Out->layout = ref.layout;
ref2Out->aspectMask = aspectMask;
}
void ToSubpassDescription2(const VkSubpassDescription &desc,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &resolveRefs,
const VkAttachmentReference2KHR &depthStencilRef,
VkSubpassDescription2KHR *desc2Out)
{
*desc2Out = {};
desc2Out->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
desc2Out->flags = desc.flags;
desc2Out->pipelineBindPoint = desc.pipelineBindPoint;
desc2Out->inputAttachmentCount = static_cast<uint32_t>(inputRefs.size());
desc2Out->pInputAttachments = !inputRefs.empty() ? inputRefs.data() : nullptr;
desc2Out->colorAttachmentCount = static_cast<uint32_t>(colorRefs.size());
desc2Out->pColorAttachments = !colorRefs.empty() ? colorRefs.data() : nullptr;
desc2Out->pResolveAttachments = !resolveRefs.empty() ? resolveRefs.data() : nullptr;
desc2Out->pDepthStencilAttachment = desc.pDepthStencilAttachment ? &depthStencilRef : nullptr;
desc2Out->preserveAttachmentCount = desc.preserveAttachmentCount;
desc2Out->pPreserveAttachments = desc.pPreserveAttachments;
}
void ToSubpassDependency2(const VkSubpassDependency &dep, VkSubpassDependency2KHR *dep2Out)
{
*dep2Out = {};
dep2Out->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
dep2Out->srcSubpass = dep.srcSubpass;
dep2Out->dstSubpass = dep.dstSubpass;
dep2Out->srcStageMask = dep.srcStageMask;
dep2Out->dstStageMask = dep.dstStageMask;
dep2Out->srcAccessMask = dep.srcAccessMask;
dep2Out->dstAccessMask = dep.dstAccessMask;
dep2Out->dependencyFlags = dep.dependencyFlags;
}
angle::Result CreateRenderPass2(Context *context,
const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
RenderPass *renderPass)
{
// Convert the attachments to VkAttachmentDescription2.
FramebufferAttachmentArray<VkAttachmentDescription2KHR> attachmentDescs;
for (uint32_t index = 0; index < createInfo.attachmentCount; ++index)
{
ToAttachmentDesciption2(createInfo.pAttachments[index], &attachmentDescs[index]);
}
// Convert subpass attachments to VkAttachmentReference2 and the subpass description to
// VkSubpassDescription2.
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassInputAttachmentRefs(
createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassColorAttachmentRefs(
createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassResolveAttachmentRefs(
createInfo.subpassCount);
SubpassVector<VkAttachmentReference2KHR> subpassDepthStencilAttachmentRefs(
createInfo.subpassCount);
SubpassVector<VkSubpassDescription2KHR> subpassDescriptions(createInfo.subpassCount);
for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass)
{
const VkSubpassDescription &desc = createInfo.pSubpasses[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs =
subpassInputAttachmentRefs[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs =
subpassColorAttachmentRefs[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &resolveRefs =
subpassResolveAttachmentRefs[subpass];
VkAttachmentReference2KHR &depthStencilRef = subpassDepthStencilAttachmentRefs[subpass];
inputRefs.resize(desc.inputAttachmentCount);
colorRefs.resize(desc.colorAttachmentCount);
// Convert subpass attachment references.
for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index)
{
// TODO(syoussefi): support depth/stencil unresolve. http://anglebug.com/4836
ToAttachmentReference2(desc.pInputAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
&inputRefs[index]);
}
for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
{
ToAttachmentReference2(desc.pColorAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
&colorRefs[index]);
}
if (desc.pResolveAttachments)
{
resolveRefs.resize(desc.colorAttachmentCount);
for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
{
ToAttachmentReference2(desc.pResolveAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
&resolveRefs[index]);
}
}
if (desc.pDepthStencilAttachment)
{
ToAttachmentReference2(*desc.pDepthStencilAttachment,
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
&depthStencilRef);
}
// Convert subpass itself.
ToSubpassDescription2(desc, inputRefs, colorRefs, resolveRefs, depthStencilRef,
&subpassDescriptions[subpass]);
}
// Append the depth/stencil resolve attachment to the pNext chain of last subpass.
ASSERT(depthStencilResolve.pDepthStencilResolveAttachment != nullptr);
subpassDescriptions.back().pNext = &depthStencilResolve;
// Convert subpass dependencies to VkSubpassDependency2.
std::vector<VkSubpassDependency2KHR> subpassDependencies(createInfo.dependencyCount);
for (uint32_t index = 0; index < createInfo.dependencyCount; ++index)
{
ToSubpassDependency2(createInfo.pDependencies[index], &subpassDependencies[index]);
}
// Convert CreateInfo itself
VkRenderPassCreateInfo2KHR createInfo2 = {};
createInfo2.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
createInfo2.flags = createInfo.flags;
createInfo2.attachmentCount = createInfo.attachmentCount;
createInfo2.pAttachments = attachmentDescs.data();
createInfo2.subpassCount = createInfo.subpassCount;
createInfo2.pSubpasses = subpassDescriptions.data();
createInfo2.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
createInfo2.pDependencies = !subpassDependencies.empty() ? subpassDependencies.data() : nullptr;
// Initialize the render pass.
ANGLE_VK_TRY(context, renderPass->init2(context->getDevice(), createInfo2));
return angle::Result::Continue;
}
angle::Result InitializeRenderPassFromDesc(Context *context,
const RenderPassDesc &desc, const RenderPassDesc &desc,
const AttachmentOpsArray &ops, const AttachmentOpsArray &ops,
RenderPass *renderPass) RenderPass *renderPass)
{ {
constexpr VkAttachmentReference kUnusedAttachment = {VK_ATTACHMENT_UNUSED, constexpr VkAttachmentReference kUnusedAttachment = {VK_ATTACHMENT_UNUSED,
VK_IMAGE_LAYOUT_UNDEFINED}; VK_IMAGE_LAYOUT_UNDEFINED};
constexpr VkAttachmentReference2 kUnusedAttachment2 = {
VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR, nullptr, VK_ATTACHMENT_UNUSED,
VK_IMAGE_LAYOUT_UNDEFINED, 0};
// Unpack the packed and split representation into the format required by Vulkan. // Unpack the packed and split representation into the format required by Vulkan.
gl::DrawBuffersVector<VkAttachmentReference> colorAttachmentRefs; gl::DrawBuffersVector<VkAttachmentReference> colorAttachmentRefs;
VkAttachmentReference depthStencilAttachmentRef = kUnusedAttachment;
gl::DrawBuffersVector<VkAttachmentReference> colorResolveAttachmentRefs; gl::DrawBuffersVector<VkAttachmentReference> colorResolveAttachmentRefs;
VkAttachmentReference depthStencilAttachmentRef = kUnusedAttachment;
VkAttachmentReference2KHR depthStencilResolveAttachmentRef = kUnusedAttachment2;
// The list of attachments includes all non-resolve and resolve attachments. // The list of attachments includes all non-resolve and resolve attachments.
FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs; FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs;
...@@ -540,13 +731,32 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -540,13 +731,32 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
colorResolveAttachmentRefs.push_back(colorRef); colorResolveAttachmentRefs.push_back(colorRef);
UnpackResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format, UnpackColorResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format,
desc.hasColorUnresolveAttachment(colorIndexGL)); desc.hasColorUnresolveAttachment(colorIndexGL));
++attachmentCount; ++attachmentCount;
} }
SubpassList subpassDesc; // Pack depth/stencil resolve attachment, if any
if (desc.hasDepthStencilResolveAttachment())
{
ASSERT(desc.hasDepthStencilAttachment());
uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
const vk::Format &format = context->getRenderer()->getFormat(desc[depthStencilIndexGL]);
depthStencilResolveAttachmentRef.attachment = attachmentCount.get();
depthStencilResolveAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilResolveAttachmentRef.aspectMask =
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
UnpackDepthStencilResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format);
++attachmentCount;
}
SubpassVector<VkSubpassDescription> subpassDesc;
// If any attachment needs to be unresolved, create an initial subpass for this purpose. Note // If any attachment needs to be unresolved, create an initial subpass for this purpose. Note
// that the following arrays are used in initializing a VkSubpassDescription in subpassDesc, // that the following arrays are used in initializing a VkSubpassDescription in subpassDesc,
...@@ -554,14 +764,14 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -554,14 +764,14 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
// same scope. // same scope.
gl::DrawBuffersVector<VkAttachmentReference> unresolveColorAttachmentRefs; gl::DrawBuffersVector<VkAttachmentReference> unresolveColorAttachmentRefs;
gl::DrawBuffersVector<VkAttachmentReference> unresolveInputAttachmentRefs; gl::DrawBuffersVector<VkAttachmentReference> unresolveInputAttachmentRefs;
gl::DrawBuffersVector<uint32_t> unresolvePreserveAttachmentRefs; FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs;
if (desc.getColorUnresolveAttachmentMask().any()) if (desc.getColorUnresolveAttachmentMask().any())
{ {
subpassDesc.push_back({}); subpassDesc.push_back({});
InitializeUnresolveSubpass(desc, colorAttachmentRefs, colorResolveAttachmentRefs, InitializeUnresolveSubpass(desc, colorAttachmentRefs, colorResolveAttachmentRefs,
depthStencilAttachmentRef, &unresolveColorAttachmentRefs, depthStencilAttachmentRef, depthStencilResolveAttachmentRef,
&unresolveInputAttachmentRefs, &unresolvePreserveAttachmentRefs, &unresolveColorAttachmentRefs, &unresolveInputAttachmentRefs,
&subpassDesc.back()); &unresolvePreserveAttachmentRefs, &subpassDesc.back());
} }
subpassDesc.push_back({}); subpassDesc.push_back({});
...@@ -582,6 +792,23 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -582,6 +792,23 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
applicationSubpass->preserveAttachmentCount = 0; applicationSubpass->preserveAttachmentCount = 0;
applicationSubpass->pPreserveAttachments = nullptr; applicationSubpass->pPreserveAttachments = nullptr;
// If depth/stencil is to be resolved, add a VkSubpassDescriptionDepthStencilResolve to the
// pNext chain of the subpass description. Note that we need a VkSubpassDescription2KHR to have
// a pNext pointer. CreateRenderPass2 is called to convert the data structures here to those
// specified by VK_KHR_create_renderpass2 for this purpose.
VkSubpassDescriptionDepthStencilResolve depthStencilResolve = {};
if (desc.hasDepthStencilResolveAttachment())
{
depthStencilResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
depthStencilResolve.depthResolveMode = desc.hasDepthResolveAttachment()
? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
: VK_RESOLVE_MODE_NONE;
depthStencilResolve.stencilResolveMode = desc.hasStencilResolveAttachment()
? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
: VK_RESOLVE_MODE_NONE;
depthStencilResolve.pDepthStencilResolveAttachment = &depthStencilResolveAttachmentRef;
}
std::vector<VkSubpassDependency> subpassDependencies; std::vector<VkSubpassDependency> subpassDependencies;
if (desc.getColorUnresolveAttachmentMask().any()) if (desc.getColorUnresolveAttachmentMask().any())
{ {
...@@ -604,7 +831,16 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -604,7 +831,16 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
createInfo.pDependencies = subpassDependencies.data(); createInfo.pDependencies = subpassDependencies.data();
} }
ANGLE_VK_TRY(context, renderPass->init(context->getDevice(), createInfo)); // If depth/stencil resolve is used, we need to create the render pass with
// vkCreateRenderPass2KHR.
if (desc.hasDepthStencilResolveAttachment())
{
ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve, renderPass));
}
else
{
ANGLE_VK_TRY(context, renderPass->init(context->getDevice(), createInfo));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -821,6 +1057,24 @@ void RenderPassDesc::removeColorUnresolveAttachment(size_t colorIndexGL) ...@@ -821,6 +1057,24 @@ void RenderPassDesc::removeColorUnresolveAttachment(size_t colorIndexGL)
mColorUnresolveAttachmentMask.reset(colorIndexGL); mColorUnresolveAttachmentMask.reset(colorIndexGL);
} }
void RenderPassDesc::packDepthStencilResolveAttachment(bool resolveDepth, bool resolveStencil)
{
ASSERT(hasDepthStencilAttachment());
ASSERT(!hasDepthStencilResolveAttachment());
static_assert((kDepthStencilFormatStorageMask & (kResolveDepthFlag | kResolveStencilFlag)) == 0,
"Collision in depth/stencil format and flag bits");
if (resolveDepth)
{
mAttachmentFormats.back() |= kResolveDepthFlag;
}
if (resolveStencil)
{
mAttachmentFormats.back() |= kResolveStencilFlag;
}
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other) RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{ {
memcpy(this, &other, sizeof(RenderPassDesc)); memcpy(this, &other, sizeof(RenderPassDesc));
...@@ -848,9 +1102,11 @@ size_t RenderPassDesc::attachmentCount() const ...@@ -848,9 +1102,11 @@ size_t RenderPassDesc::attachmentCount() const
} }
// Note that there are no gaps in depth/stencil attachments. In fact there is a maximum of 1 of // Note that there are no gaps in depth/stencil attachments. In fact there is a maximum of 1 of
// it. // it + 1 for its resolve attachment.
size_t depthStencilCount = hasDepthStencilAttachment() ? 1 : 0; size_t depthStencilCount = hasDepthStencilAttachment() ? 1 : 0;
return colorAttachmentCount + mColorResolveAttachmentMask.count() + depthStencilCount; size_t depthStencilResolveCount = hasDepthStencilResolveAttachment() ? 1 : 0;
return colorAttachmentCount + mColorResolveAttachmentMask.count() + depthStencilCount +
depthStencilResolveCount;
} }
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs) bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
...@@ -2183,7 +2439,7 @@ void FramebufferDesc::updateColor(uint32_t index, ImageViewSubresourceSerial ser ...@@ -2183,7 +2439,7 @@ void FramebufferDesc::updateColor(uint32_t index, ImageViewSubresourceSerial ser
void FramebufferDesc::updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial) void FramebufferDesc::updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial)
{ {
update(kFramebufferDescResolveIndexOffset + index, serial); update(kFramebufferDescColorResolveIndexOffset + index, serial);
} }
void FramebufferDesc::updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask) void FramebufferDesc::updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask)
...@@ -2196,6 +2452,11 @@ void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial) ...@@ -2196,6 +2452,11 @@ void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial)
update(kFramebufferDescDepthStencilIndex, serial); update(kFramebufferDescDepthStencilIndex, serial);
} }
void FramebufferDesc::updateDepthStencilResolve(ImageViewSubresourceSerial serial)
{
update(kFramebufferDescDepthStencilResolveIndexOffset, serial);
}
void FramebufferDesc::updateReadOnlyDepth(bool readOnlyDepth) void FramebufferDesc::updateReadOnlyDepth(bool readOnlyDepth)
{ {
mReadOnlyDepth = readOnlyDepth; mReadOnlyDepth = readOnlyDepth;
......
...@@ -108,10 +108,12 @@ inline void UpdateAccess(ResourceAccess *oldAccess, ResourceAccess newAccess) ...@@ -108,10 +108,12 @@ inline void UpdateAccess(ResourceAccess *oldAccess, ResourceAccess newAccess)
} }
// There can be a maximum of IMPLEMENTATION_MAX_DRAW_BUFFERS color and resolve attachments, plus one // There can be a maximum of IMPLEMENTATION_MAX_DRAW_BUFFERS color and resolve attachments, plus one
// depth/stencil attachment. // depth/stencil attachment and one depth/stencil resolve attachment.
constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 + 1; constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 + 2;
template <typename T> template <typename T>
using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>; using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>;
template <typename T>
using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>;
constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1; constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
template <typename T> template <typename T>
...@@ -140,6 +142,8 @@ class alignas(4) RenderPassDesc final ...@@ -140,6 +142,8 @@ class alignas(4) RenderPassDesc final
// Indicate that a color attachment should take its data from the resolve attachment initially. // Indicate that a color attachment should take its data from the resolve attachment initially.
void packColorUnresolveAttachment(size_t colorIndexGL); void packColorUnresolveAttachment(size_t colorIndexGL);
void removeColorUnresolveAttachment(size_t colorIndexGL); void removeColorUnresolveAttachment(size_t colorIndexGL);
// Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
void packDepthStencilResolveAttachment(bool resolveDepth, bool resolveStencil);
size_t hash() const; size_t hash() const;
...@@ -165,6 +169,18 @@ class alignas(4) RenderPassDesc final ...@@ -165,6 +169,18 @@ class alignas(4) RenderPassDesc final
{ {
return mColorUnresolveAttachmentMask.test(colorIndexGL); return mColorUnresolveAttachmentMask.test(colorIndexGL);
} }
bool hasDepthStencilResolveAttachment() const
{
return (mAttachmentFormats.back() & (kResolveDepthFlag | kResolveStencilFlag)) != 0;
}
bool hasDepthResolveAttachment() const
{
return (mAttachmentFormats.back() & kResolveDepthFlag) != 0;
}
bool hasStencilResolveAttachment() const
{
return (mAttachmentFormats.back() & kResolveStencilFlag) != 0;
}
// Get the number of attachments in the Vulkan render pass, i.e. after removing disabled // Get the number of attachments in the Vulkan render pass, i.e. after removing disabled
// color attachments. // color attachments.
...@@ -241,6 +257,10 @@ class alignas(4) RenderPassDesc final ...@@ -241,6 +257,10 @@ class alignas(4) RenderPassDesc final
// Depth/stencil format is stored in 3 bits. // Depth/stencil format is stored in 3 bits.
static constexpr uint8_t kDepthStencilFormatStorageMask = 0x7; static constexpr uint8_t kDepthStencilFormatStorageMask = 0x7;
// Flags stored in the upper 5 bits of mAttachmentFormats.back().
static constexpr uint8_t kResolveDepthFlag = 0x80;
static constexpr uint8_t kResolveStencilFlag = 0x40;
}; };
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs); bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
...@@ -1016,11 +1036,15 @@ class UniformsAndXfbDesc ...@@ -1016,11 +1036,15 @@ class UniformsAndXfbDesc
// In the FramebufferDesc object: // In the FramebufferDesc object:
// - Depth/stencil serial is at index 0 // - Depth/stencil serial is at index 0
// - Color serials are at indices [1:gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] // - Color serials are at indices [1:gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]
// - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1, // - Depth/stencil resolve attachment is at index gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1
// gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2] // - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2,
constexpr size_t kFramebufferDescDepthStencilIndex = 0; // gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1]
constexpr size_t kFramebufferDescColorIndexOffset = 1; constexpr size_t kFramebufferDescDepthStencilIndex = 0;
constexpr size_t kFramebufferDescResolveIndexOffset = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1; constexpr size_t kFramebufferDescColorIndexOffset = kFramebufferDescDepthStencilIndex + 1;
constexpr size_t kFramebufferDescDepthStencilResolveIndexOffset =
kFramebufferDescColorIndexOffset + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
constexpr size_t kFramebufferDescColorResolveIndexOffset =
kFramebufferDescDepthStencilResolveIndexOffset + 1;
class FramebufferDesc class FramebufferDesc
{ {
...@@ -1035,6 +1059,7 @@ class FramebufferDesc ...@@ -1035,6 +1059,7 @@ class FramebufferDesc
void updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial); void updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial);
void updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask); void updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask);
void updateDepthStencil(ImageViewSubresourceSerial serial); void updateDepthStencil(ImageViewSubresourceSerial serial);
void updateDepthStencilResolve(ImageViewSubresourceSerial serial);
void updateReadOnlyDepth(bool readOnlyDepth); void updateReadOnlyDepth(bool readOnlyDepth);
size_t hash() const; size_t hash() const;
void reset(); void reset();
......
...@@ -833,6 +833,9 @@ PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR ...@@ -833,6 +833,9 @@ PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR = nullptr; PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR = nullptr;
PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR = nullptr; PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR = nullptr;
// VK_KHR_create_renderpass2
PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
# if defined(ANGLE_PLATFORM_FUCHSIA) # if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface // VK_FUCHSIA_imagepipe_surface
PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr; PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
...@@ -900,6 +903,12 @@ void InitSamplerYcbcrKHRFunctions(VkDevice device) ...@@ -900,6 +903,12 @@ void InitSamplerYcbcrKHRFunctions(VkDevice device)
GET_DEVICE_FUNC(vkDestroySamplerYcbcrConversionKHR); GET_DEVICE_FUNC(vkDestroySamplerYcbcrConversionKHR);
} }
// VK_KHR_create_renderpass2
void InitRenderPass2KHRFunctions(VkDevice device)
{
GET_DEVICE_FUNC(vkCreateRenderPass2KHR);
}
# if defined(ANGLE_PLATFORM_FUCHSIA) # if defined(ANGLE_PLATFORM_FUCHSIA)
void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance) void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance)
{ {
......
...@@ -802,6 +802,7 @@ void InitDebugReportEXTFunctions(VkInstance instance); ...@@ -802,6 +802,7 @@ void InitDebugReportEXTFunctions(VkInstance instance);
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance); void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance);
void InitTransformFeedbackEXTFunctions(VkDevice device); void InitTransformFeedbackEXTFunctions(VkDevice device);
void InitSamplerYcbcrKHRFunctions(VkDevice device); void InitSamplerYcbcrKHRFunctions(VkDevice device);
void InitRenderPass2KHRFunctions(VkDevice device);
# if defined(ANGLE_PLATFORM_FUCHSIA) # if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface // VK_FUCHSIA_imagepipe_surface
......
...@@ -513,6 +513,7 @@ class RenderPass final : public WrappedObject<RenderPass, VkRenderPass> ...@@ -513,6 +513,7 @@ class RenderPass final : public WrappedObject<RenderPass, VkRenderPass>
void destroy(VkDevice device); void destroy(VkDevice device);
VkResult init(VkDevice device, const VkRenderPassCreateInfo &createInfo); VkResult init(VkDevice device, const VkRenderPassCreateInfo &createInfo);
VkResult init2(VkDevice device, const VkRenderPassCreateInfo2 &createInfo);
}; };
enum class StagingUsage enum class StagingUsage
...@@ -1501,6 +1502,12 @@ ANGLE_INLINE VkResult RenderPass::init(VkDevice device, const VkRenderPassCreate ...@@ -1501,6 +1502,12 @@ ANGLE_INLINE VkResult RenderPass::init(VkDevice device, const VkRenderPassCreate
return vkCreateRenderPass(device, &createInfo, nullptr, &mHandle); return vkCreateRenderPass(device, &createInfo, nullptr, &mHandle);
} }
ANGLE_INLINE VkResult RenderPass::init2(VkDevice device, const VkRenderPassCreateInfo2 &createInfo)
{
ASSERT(!valid());
return vkCreateRenderPass2KHR(device, &createInfo, nullptr, &mHandle);
}
// Buffer implementation. // Buffer implementation.
ANGLE_INLINE void Buffer::destroy(VkDevice device) ANGLE_INLINE void Buffer::destroy(VkDevice device)
{ {
......
...@@ -142,7 +142,6 @@ class MultisampledRenderToTextureTest : public ANGLETest ...@@ -142,7 +142,6 @@ class MultisampledRenderToTextureTest : public ANGLETest
void drawCopyThenBlendCommon(bool useRenderbuffer); void drawCopyThenBlendCommon(bool useRenderbuffer);
void clearDrawCopyThenBlendSameProgramCommon(bool useRenderbuffer); void clearDrawCopyThenBlendSameProgramCommon(bool useRenderbuffer);
void clearThenBlendCommon(bool useRenderbuffer); void clearThenBlendCommon(bool useRenderbuffer);
void depthStencilClearThenDrawCommon(bool useRenderbuffer);
GLProgram mCopyTextureProgram; GLProgram mCopyTextureProgram;
GLint mCopyTextureUniformLocation = -1; GLint mCopyTextureUniformLocation = -1;
...@@ -153,6 +152,7 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes ...@@ -153,6 +152,7 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes
protected: protected:
void readPixelsTestCommon(bool useRenderbuffer); void readPixelsTestCommon(bool useRenderbuffer);
void blitFramebufferTestCommon(bool useRenderbuffer); void blitFramebufferTestCommon(bool useRenderbuffer);
void depthStencilClearThenDrawCommon(bool useRenderbuffer);
void colorAttachment1Common(bool useRenderbuffer); void colorAttachment1Common(bool useRenderbuffer);
void colorAttachments0And3Common(bool useRenderbuffer); void colorAttachments0And3Common(bool useRenderbuffer);
void blitFramebufferMixedColorAndDepthCommon(bool useRenderbuffer); void blitFramebufferMixedColorAndDepthCommon(bool useRenderbuffer);
...@@ -1176,13 +1176,17 @@ TEST_P(MultisampledRenderToTextureTest, RenderbufferClearThenBlend) ...@@ -1176,13 +1176,17 @@ TEST_P(MultisampledRenderToTextureTest, RenderbufferClearThenBlend)
clearThenBlendCommon(true); clearThenBlendCommon(true);
} }
void MultisampledRenderToTextureTest::depthStencilClearThenDrawCommon(bool useRenderbuffer) void MultisampledRenderToTextureES3Test::depthStencilClearThenDrawCommon(bool useRenderbuffer)
{ {
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
if (!useRenderbuffer) if (!useRenderbuffer)
{ {
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2"));
} }
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
constexpr GLsizei kSize = 64; constexpr GLsizei kSize = 64;
setupCopyTexProgram(); setupCopyTexProgram();
...@@ -1211,7 +1215,7 @@ void MultisampledRenderToTextureTest::depthStencilClearThenDrawCommon(bool useRe ...@@ -1211,7 +1215,7 @@ void MultisampledRenderToTextureTest::depthStencilClearThenDrawCommon(bool useRe
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);
// If stencil is not clear to 0x55, rendering would fail. // If stencil is not cleared to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF); glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
...@@ -1238,15 +1242,104 @@ void MultisampledRenderToTextureTest::depthStencilClearThenDrawCommon(bool useRe ...@@ -1238,15 +1242,104 @@ void MultisampledRenderToTextureTest::depthStencilClearThenDrawCommon(bool useRe
} }
// Clear depth stencil, then draw. The clear should be applied correctly. // Clear depth stencil, then draw. The clear should be applied correctly.
TEST_P(MultisampledRenderToTextureTest, DepthStencilClearThenDraw) TEST_P(MultisampledRenderToTextureES3Test, DepthStencilClearThenDraw)
{ {
clearThenBlendCommon(false); depthStencilClearThenDrawCommon(false);
} }
// Clear depth stencil, then draw. The clear should be applied correctly. Uses renderbuffer. // Clear depth stencil, then draw. The clear should be applied correctly. Uses renderbuffer.
TEST_P(MultisampledRenderToTextureTest, RenderbufferDepthStencilClearThenDraw) TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearThenDraw)
{ {
clearThenBlendCommon(true); depthStencilClearThenDrawCommon(true);
}
// Clear&Draw, copy, then blend similarly to RenderbufferClearDrawCopyThenBlendSameProgram. This
// tests uses a depth/stencil buffer and makes sure the second draw (in the second render pass)
// succeeds (i.e. depth/stencil data is not lost). Note that this test doesn't apply to
// depth/stencil textures as they are explicitly autoinvalidated between render passes.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopyThenBlend)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create framebuffer to draw into, with both color and depth attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color,
0, 4);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Set viewport and clear depth/stencil
glViewport(0, 0, kSize, kSize);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not cleared to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Draw again into the framebuffer, this time blending. This tests that both the color and
// depth/stencil data are preserved after the resolve incurred by the copy above.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now yellow
const GLColor kExpected(127, 127, 0, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red.
const GLColor expectedCopyResult(255, 0, 0, 255);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
} }
void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbuffer) void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbuffer)
......
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