Commit d856ca48 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: add clear test for emulated stencil or depth formats

S8_UINT and D24_UNORM_X8_UINT are the only formats currently that are single-aspect and are possibly emulated with a packed depth-stencil format if it's not supported. A flag to FeaturesVk has been added as a way to force this behavior for the sake of testing. This test is added to ensure the correct clear algorithm is used for this case. Additionally, this case is detected and the other aspect is forcefully cleared to 0 whenever the original aspect is cleared. Bug: angleproject:2815 Change-Id: Ief3039d66bbf46468213b9e3224f7cc7541c3a2e Reviewed-on: https://chromium-review.googlesource.com/c/1312453 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 743899de
......@@ -3,14 +3,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_helpers:
// Optional features for the Vulkan renderer.
// FeaturesVk.h: Optional features for the Vulkan renderer.
//
#ifndef LIBANGLE_RENDERER_VULKAN_FEATURESVK_H_
#define LIBANGLE_RENDERER_VULKAN_FEATURESVK_H_
#ifndef ANGLE_PLATFORM_FEATURESVK_H_
#define ANGLE_PLATFORM_FEATURESVK_H_
namespace rx
namespace angle
{
struct FeaturesVk
{
// Line segment rasterization must follow OpenGL rules. This means using an algorithm similar
......@@ -37,7 +38,13 @@ struct FeaturesVk
// Add an extra copy region when using vkCmdCopyBuffer as the Windows Intel driver seems
// to have a bug where the last region is ignored.
bool extraCopyBufferRegion = false;
// This flag is added for the sole purpose of end2end tests, to test the correctness
// of various algorithms when a fallback format is used, such as using a packed format to
// emulate a depth- or stencil-only format.
bool forceFallbackFormat = false;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_FEATURESVK_H_
} // namespace angle
#endif // ANGLE_PLATFORM_FEATURESVK_H_
......@@ -36,6 +36,7 @@
namespace angle
{
struct WorkaroundsD3D;
struct FeaturesVk;
using TraceEventHandle = uint64_t;
using EGLDisplayType = void *;
struct PlatformMethods;
......@@ -233,6 +234,13 @@ inline void DefaultOverrideWorkaroundsD3D(PlatformMethods *platform,
{
}
using OverrideFeaturesVkFunc = void (*)(PlatformMethods *platform,
angle::FeaturesVk *workaroundsVulkan);
inline void DefaultOverrideFeaturesVk(PlatformMethods *platform,
angle::FeaturesVk *workaroundsVulkan)
{
}
// Callback on a successful program link with the program binary. Can be used to store
// shaders to disk. Keys are a 160-bit SHA-1 hash.
using ProgramKeyType = std::array<uint8_t, 20>;
......@@ -262,6 +270,7 @@ inline void DefaultCacheProgram(PlatformMethods *platform,
OP(histogramSparse, HistogramSparse) \
OP(histogramBoolean, HistogramBoolean) \
OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \
OP(overrideFeaturesVk, OverrideFeaturesVk) \
OP(cacheProgram, CacheProgram)
#define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName;
......
......@@ -1142,7 +1142,7 @@ VkColorComponentFlags ContextVk::getClearColorMask() const
return mClearColorMask;
}
const FeaturesVk &ContextVk::getFeatures() const
const angle::FeaturesVk &ContextVk::getFeatures() const
{
return mRenderer->getFeatures();
}
......
......@@ -16,9 +16,13 @@
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
namespace angle
{
struct FeaturesVk;
}
namespace rx
{
class RendererVk;
class ContextVk : public ContextImpl, public vk::Context
......@@ -157,7 +161,7 @@ class ContextVk : public ContextImpl, public vk::Context
angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
VkDevice getDevice() const;
const FeaturesVk &getFeatures() const;
const angle::FeaturesVk &getFeatures() const;
void invalidateVertexAndIndexBuffers();
void invalidateDefaultAttribute(size_t attribIndex);
......
......@@ -187,9 +187,37 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
bool clearColor = IsMaskFlagSet(static_cast<int>(mask), GL_COLOR_BUFFER_BIT);
const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthStencilAttachment();
const gl::State &glState = context->getGLState();
VkClearDepthStencilValue clearDepthStencilValue =
contextVk->getClearDepthStencilValue().depthStencil;
// Apply the stencil mask to the clear value.
clearDepthStencilValue.stencil &=
contextVk->getGLState().getDepthStencilState().stencilWritemask;
// If the depth or stencil is being cleared, and the image was originally requested to have a
// single aspect, but it's emulated with a depth/stencil format, clear both aspects, setting the
// other aspect to 0.
if (clearStencil || clearDepth)
{
RenderTargetVk *depthStencil = mRenderTargetCache.getDepthStencil();
const vk::Format &format = depthStencil->getImageFormat();
// GL_DEPTH_COMPONENT24 is always emulated with a format that has stencil.
if (format.angleFormat().stencilBits == 0)
{
clearStencil = true;
clearDepthStencilValue.stencil = 0;
}
// GL_STENCIL_INDEX8 may or may not be emulated.
else if (format.angleFormat().depthBits == 0 && format.vkTextureFormat != VK_FORMAT_S8_UINT)
{
clearDepth = true;
clearDepthStencilValue.depth = 0;
}
}
// The most costly clear mode is when we need to mask out specific color channels. This can
// only be done with a draw call. The scissor region however can easily be integrated with
// this method. Similarly for depth/stencil clear.
......@@ -206,24 +234,19 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
if (clearDepth || clearStencil)
{
ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil));
ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil,
clearDepthStencilValue));
}
return angle::Result::Continue();
}
// If we clear the depth OR the stencil but not both, and we have a packed depth stencil
// attachment, we need to use clearAttachments instead of clearDepthStencil since Vulkan won't
// allow us to clear one or the other separately.
// Note: this might be bugged if we emulate single depth or stencil with a packed format.
// TODO(jmadill): Investigate emulated packed formats. http://anglebug.com/2815
bool isSingleClearOnPackedDepthStencilAttachment =
depthStencilAttachment && (clearDepth != clearStencil);
if (glState.isScissorTestEnabled() || isSingleClearOnPackedDepthStencilAttachment)
if (glState.isScissorTestEnabled())
{
// With scissor test enabled, we clear very differently and we don't need to access
// the image inside each attachment we can just use clearCmdAttachments with our
// scissor region instead.
ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil));
ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil,
clearDepthStencilValue));
return angle::Result::Continue();
}
......@@ -232,19 +255,22 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
{
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
VkClearDepthStencilValue clearDepthStencilValue =
contextVk->getClearDepthStencilValue().depthStencil;
// Apply the stencil mask to the clear value.
clearDepthStencilValue.stencil &=
contextVk->getGLState().getDepthStencilState().stencilWritemask;
RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil();
const angle::Format &format = renderTarget->getImageFormat().textureFormat();
const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format);
VkImageAspectFlags clearAspects = aspectFlags;
if (!clearDepth)
{
clearAspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (!clearStencil)
{
clearAspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
}
vk::ImageHelper *image = renderTarget->getImageForWrite(&mFramebuffer);
image->clearDepthStencil(aspectFlags, clearDepthStencilValue, commandBuffer);
image->clearDepthStencil(aspectFlags, clearAspects, clearDepthStencilValue, commandBuffer);
}
if (!clearColor)
......@@ -875,10 +901,12 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe
return angle::Result::Continue();
}
angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
angle::Result FramebufferVk::clearWithClearAttachments(
ContextVk *contextVk,
bool clearColor,
bool clearDepth,
bool clearStencil)
bool clearStencil,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
// Trigger a new command node to ensure overlapping writes happen sequentially.
mFramebuffer.finishCurrentCommands(contextVk->getRenderer());
......@@ -939,15 +967,8 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
}
}
VkClearValue depthStencilClearValue = contextVk->getClearDepthStencilValue();
// Apply the stencil mask to the clear value. Stencil mask is generally respected through the
// respective pipeline state, but clear uses its own special function.
if (clearStencil)
{
depthStencilClearValue.depthStencil.stencil &=
contextVk->getGLState().getDepthStencilState().stencilWritemask;
}
VkClearValue depthStencilClearValue = {};
depthStencilClearValue.depthStencil = clearDepthStencilValue;
if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr)
{
......
......@@ -161,7 +161,8 @@ class FramebufferVk : public FramebufferImpl
angle::Result clearWithClearAttachments(ContextVk *contextVk,
bool clearColor,
bool clearDepth,
bool clearStencil);
bool clearStencil,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, VkColorComponentFlags colorMaskFlags);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
......
......@@ -89,7 +89,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
if (isDepthOrStencilFormat)
{
mImage.clearDepthStencil(aspect, kDefaultClearDepthStencilValue, commandBuffer);
mImage.clearDepthStencil(aspect, aspect, kDefaultClearDepthStencilValue, commandBuffer);
}
else
{
......
......@@ -531,7 +531,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
GlslangWrapper::Initialize();
// Initialize the format table.
mFormatTable.initialize(mPhysicalDevice, &mNativeTextureCaps,
mFormatTable.initialize(mPhysicalDevice, mFeatures, &mNativeTextureCaps,
&mNativeCaps.compressedTextureFormats);
return angle::Result::Continue();
......@@ -751,6 +751,9 @@ void RendererVk::initFeatures()
// http://anglebug.com/2838
mFeatures.extraCopyBufferRegion = IsIntel(mPhysicalDeviceProperties.vendorID);
#endif
angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesVk(platform, &mFeatures);
}
void RendererVk::initPipelineCacheVkKey()
......
......@@ -17,7 +17,6 @@
#include "libANGLE/BlobCache.h"
#include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/FeaturesVk.h"
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
......@@ -171,7 +170,7 @@ class RendererVk : angle::NonCopyable
Serial issueShaderSerial();
vk::ShaderLibrary *getShaderLibrary();
const FeaturesVk &getFeatures() const { return mFeatures; }
const angle::FeaturesVk &getFeatures() const { return mFeatures; }
angle::Result getTimestamp(vk::Context *context, uint64_t *timestampOut);
......@@ -226,7 +225,7 @@ class RendererVk : angle::NonCopyable
mutable gl::TextureCapsMap mNativeTextureCaps;
mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations;
mutable FeaturesVk mFeatures;
mutable angle::FeaturesVk mFeatures;
VkInstance mInstance;
bool mEnableValidationLayers;
......
......@@ -529,7 +529,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
// Clear the image.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mDepthStencilImage.recordCommands(displayVk, &commandBuffer));
mDepthStencilImage.clearDepthStencil(aspect, depthStencilClearValue, commandBuffer);
mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer);
ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect,
gl::SwizzleState(), &mDepthStencilImageView, 1));
......
......@@ -41,7 +41,9 @@ namespace rx
namespace vk
{{
void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &angleFormat)
void Format::initialize(VkPhysicalDevice physicalDevice,
const angle::Format &angleFormat,
const angle::FeaturesVk &featuresVk)
{{
switch (angleFormat.id)
{{
......@@ -77,7 +79,7 @@ texture_struct_template="{{{texture}, {vk_texture_format}, {texture_initializer}
texture_fallback_template = """{{
static constexpr TextureFormatInitInfo kInfo[] = {{{texture_list}}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo));
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}}"""
buffer_basic_template = """bufferFormatID = {buffer};
......@@ -97,12 +99,16 @@ initBufferFallback(physicalDevice, kInfo, ArraySize(kInfo));
def is_packed(format_id):
return "true" if "_PACK" in format_id else "false"
def gen_format_case(angle, internal_format, vk_json_data):
vk_map = vk_json_data["map"]
vk_overrides = vk_json_data["overrides"]
vk_fallbacks = vk_json_data["fallbacks"]
args = dict(format_id=angle, internal_format=internal_format,
texture_template="", buffer_template="")
args = dict(
format_id=angle,
internal_format=internal_format,
texture_template="",
buffer_template="")
if ((angle not in vk_map) and (angle not in vk_overrides) and
(angle not in vk_fallbacks)) or angle == 'NONE':
......@@ -121,16 +127,16 @@ def gen_format_case(angle, internal_format, vk_json_data):
return dict(
texture="angle::FormatID::" + format,
vk_texture_format=vk_map[format],
texture_initializer=angle_format.get_internal_format_initializer(internal_format,
format)
)
texture_initializer=angle_format.get_internal_format_initializer(
internal_format, format))
def buffer_args(format):
return dict(
buffer="angle::FormatID::" + format,
vk_buffer_format=vk_map[format],
vk_buffer_format_is_packed=is_packed(vk_map[format]),
vertex_load_function=angle_format.get_vertex_copy_function(angle, format),
vertex_load_function=angle_format.get_vertex_copy_function(
angle, format),
vertex_load_converts='false' if angle == format else 'true',
)
......@@ -141,9 +147,9 @@ def gen_format_case(angle, internal_format, vk_json_data):
elif len(textures) > 1:
args.update(
texture_template=texture_fallback_template,
texture_list=", ".join(texture_struct_template.format(**texture_args(i))
for i in textures)
)
texture_list=", ".join(
texture_struct_template.format(**texture_args(i))
for i in textures))
buffers = get_formats(angle, "buffer")
if len(buffers) == 1:
......@@ -152,11 +158,12 @@ def gen_format_case(angle, internal_format, vk_json_data):
elif len(buffers) > 1:
args.update(
buffer_template=buffer_fallback_template,
buffer_list=", ".join(buffer_struct_template.format(**buffer_args(i)) for i in buffers)
)
buffer_list=", ".join(
buffer_struct_template.format(**buffer_args(i)) for i in buffers))
return format_entry_template.format(**args).format(**args)
input_file_name = 'vk_format_map.json'
out_file_name = 'vk_format_table'
......
......@@ -15,7 +15,6 @@
#include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FeaturesVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "vk_format_utils.h"
......
......@@ -243,16 +243,16 @@
},
"fallbacks": {
"D32_FLOAT_S8X24_UINT": {
"texture": "D24_UNORM_S8_UINT"
"texture": ["D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT"]
},
"D24_UNORM_S8_UINT": {
"texture": "D32_FLOAT_S8X24_UINT"
"texture": ["D32_FLOAT_S8X24_UINT", "D24_UNORM_S8_UINT"]
},
"D24_UNORM_X8_UINT": {
"texture": "D32_FLOAT_S8X24_UINT"
"texture": ["D32_FLOAT_S8X24_UINT", "D24_UNORM_S8_UINT"]
},
"S8_UINT": {
"texture": ["D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT"]
"texture": ["D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT", "S8_UINT"]
},
"R8_UNORM": {
......@@ -352,6 +352,5 @@
"R16G16B16A16_SSCALED": {
"buffer": "R32G32B32A32_FLOAT"
}
}
}
......@@ -22,7 +22,9 @@ namespace rx
namespace vk
{
void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &angleFormat)
void Format::initialize(VkPhysicalDevice physicalDevice,
const angle::Format &angleFormat,
const angle::FeaturesVk &featuresVk)
{
switch (angleFormat.id)
{
......@@ -535,8 +537,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{
static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr},
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo));
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}
bufferFormatID = angle::FormatID::D24_UNORM_S8_UINT;
vkBufferFormat = VK_FORMAT_D24_UNORM_S8_UINT;
......@@ -550,8 +553,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{
static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr},
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo));
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}
bufferFormatID = angle::FormatID::NONE;
vkBufferFormat = VK_FORMAT_UNDEFINED;
......@@ -577,8 +581,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{
static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo));
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr},
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}
bufferFormatID = angle::FormatID::D32_FLOAT_S8X24_UINT;
vkBufferFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;
......@@ -1813,8 +1818,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::S8_UINT, VK_FORMAT_S8_UINT, nullptr},
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr},
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo));
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
{angle::FormatID::S8_UINT, VK_FORMAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}
bufferFormatID = angle::FormatID::S8_UINT;
vkBufferFormat = VK_FORMAT_S8_UINT;
......
......@@ -71,7 +71,7 @@ int FindSupportedFormat(VkPhysicalDevice physicalDevice,
int numInfo,
SupportTest hasSupport)
{
ASSERT(numInfo > 1);
ASSERT(numInfo > 0);
const int last = numInfo - 1;
for (int i = 0; i < last; ++i)
......@@ -131,9 +131,14 @@ Format::Format()
void Format::initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info,
int numInfo)
int numInfo,
const angle::FeaturesVk &featuresVk)
{
int i = FindSupportedFormat(physicalDevice, info, numInfo, HasFullTextureFormatSupport);
size_t skip = featuresVk.forceFallbackFormat ? 1 : 0;
int i = FindSupportedFormat(physicalDevice, info + skip, numInfo - skip,
HasFullTextureFormatSupport);
i += skip;
textureFormatID = info[i].format;
vkTextureFormat = info[i].vkFormat;
textureInitializerFunction = info[i].initializer;
......@@ -186,6 +191,7 @@ FormatTable::~FormatTable()
}
void FormatTable::initialize(VkPhysicalDevice physicalDevice,
const angle::FeaturesVk &featuresVk,
gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats)
{
......@@ -193,7 +199,7 @@ void FormatTable::initialize(VkPhysicalDevice physicalDevice,
{
const auto formatID = static_cast<angle::FormatID>(formatIndex);
const angle::Format &angleFormat = angle::Format::Get(formatID);
mFormatData[formatIndex].initialize(physicalDevice, angleFormat);
mFormatData[formatIndex].initialize(physicalDevice, angleFormat, featuresVk);
const GLenum internalFormat = mFormatData[formatIndex].internalFormat;
mFormatData[formatIndex].textureLoadFunctions =
GetLoadFunctionsMap(internalFormat, mFormatData[formatIndex].textureFormatID);
......
......@@ -15,6 +15,7 @@
#include "libANGLE/renderer/Format.h"
#include "libANGLE/renderer/copyvertex.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "platform/FeaturesVk.h"
#include <array>
......@@ -56,11 +57,14 @@ struct Format final : private angle::NonCopyable
bool valid() const { return internalFormat != 0; }
// This is an auto-generated method in vk_format_table_autogen.cpp.
void initialize(VkPhysicalDevice physicalDevice, const angle::Format &angleFormat);
void initialize(VkPhysicalDevice physicalDevice,
const angle::Format &angleFormat,
const angle::FeaturesVk &featuresVk);
void initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info,
int numInfo);
int numInfo,
const angle::FeaturesVk &featuresVk);
void initBufferFallback(VkPhysicalDevice physicalDevice,
const BufferFormatInitInfo *info,
int numInfo);
......@@ -93,6 +97,7 @@ class FormatTable final : angle::NonCopyable
// Also initializes the TextureCapsMap and the compressedTextureCaps in the Caps instance.
void initialize(VkPhysicalDevice physicalDevice,
const angle::FeaturesVk &featuresVk,
gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats);
......
......@@ -1238,18 +1238,19 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color,
commandBuffer->clearColorImage(mImage, mCurrentLayout, color, 1, &range);
}
void ImageHelper::clearDepthStencil(VkImageAspectFlags aspectFlags,
void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil,
CommandBuffer *commandBuffer)
{
ASSERT(valid());
changeLayoutWithStages(aspectFlags, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
changeLayoutWithStages(imageAspectFlags, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer);
VkImageSubresourceRange clearRange = {
/*aspectMask*/ aspectFlags,
/*aspectMask*/ clearAspectFlags,
/*baseMipLevel*/ 0,
/*levelCount*/ 1,
/*baseArrayLayer*/ 0,
......
......@@ -471,7 +471,8 @@ class ImageHelper final : public RecordableGraphResource
uint32_t layerCount,
CommandBuffer *commandBuffer);
void clearDepthStencil(VkImageAspectFlags aspectFlags,
void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil,
CommandBuffer *commandBuffer);
gl::Extents getSize(const gl::ImageIndex &index) const;
......
......@@ -108,6 +108,7 @@ libangle_includes = [
"include/GLSLANG/ShaderLang.h",
"include/GLSLANG/ShaderVars.h",
"include/KHR/khrplatform.h",
"include/platform/FeaturesVk.h",
"include/platform/Platform.h",
"include/platform/WorkaroundsD3D.h",
]
......@@ -747,7 +748,6 @@ libangle_vulkan_sources = [
"src/libANGLE/renderer/vulkan/DeviceVk.h",
"src/libANGLE/renderer/vulkan/DisplayVk.cpp",
"src/libANGLE/renderer/vulkan/DisplayVk.h",
"src/libANGLE/renderer/vulkan/FeaturesVk.h",
"src/libANGLE/renderer/vulkan/FenceNVVk.cpp",
"src/libANGLE/renderer/vulkan/FenceNVVk.h",
"src/libANGLE/renderer/vulkan/FramebufferVk.cpp",
......
......@@ -6,6 +6,7 @@
#include "test_utils/ANGLETest.h"
#include "platform/FeaturesVk.h"
#include "random_utils.h"
#include "shader_utils.h"
#include "test_utils/gl_raii.h"
......@@ -85,6 +86,9 @@ class ClearTest : public ClearTestBase
bool scissor,
bool clearDepth,
bool clearStencil);
bool mHasDepth = true;
bool mHasStencil = true;
};
class ClearTestES3 : public ClearTestBase
......@@ -108,6 +112,77 @@ class ScissoredClearTest : public ClearTest
{
};
class VulkanClearTest : public ClearTest
{
protected:
void SetUp() override
{
ANGLETest::SetUp();
glBindTexture(GL_TEXTURE_2D, mColorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
// Setup Color/Stencil FBO with a stencil format that's emulated with packed depth/stencil.
glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTexture,
0);
glBindRenderbuffer(GL_RENDERBUFFER, mStencilTexture);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(),
getWindowHeight());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mStencilTexture);
ASSERT_GL_NO_ERROR();
// Note: GL_DEPTH_COMPONENT24 is not allowed in GLES2.
if (getClientMajorVersion() >= 3)
{
// Setup Color/Depth FBO with a depth format that's emulated with packed depth/stencil.
glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mColorTexture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthTexture);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(),
getWindowHeight());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
mDepthTexture);
}
ASSERT_GL_NO_ERROR();
}
void TearDown() override { ANGLETest::TearDown(); }
void bindColorStencilFBO()
{
glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO);
mHasDepth = false;
}
void bindColorDepthFBO()
{
glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO);
mHasStencil = false;
}
// Override a feature to force emulation of stencil-only and depth-only formats with a packed
// depth/stencil format
void overrideFeaturesVk(FeaturesVk *featuresVk) override
{
featuresVk->forceFallbackFormat = true;
}
private:
GLFramebuffer mColorStencilFBO;
GLFramebuffer mColorDepthFBO;
GLTexture mColorTexture;
GLRenderbuffer mDepthTexture;
GLRenderbuffer mStencilTexture;
};
// Test clearing the default framebuffer
TEST_P(ClearTest, DefaultFramebuffer)
{
......@@ -546,12 +621,12 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
const int whalf = w >> 1;
const int hhalf = h >> 1;
// Clear to a random color, 1.0 depth and 0x00 stencil
// Clear to a random color, 0.9 depth and 0x00 stencil
Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f);
GLColor color1RGB(color1);
glClearColor(color1[0], color1[1], color1[2], color1[3]);
glClearDepthf(1.0f);
glClearDepthf(0.9f);
glClearStencil(0x00);
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
......@@ -583,69 +658,83 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glStencilMask(0xFF);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
ASSERT_GL_NO_ERROR();
// Verify second clear mask worked as expected.
GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]);
GLColor expectedColorRGB = mask ? color2MaskedRGB : color2RGB;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedColorRGB, 1);
GLColor expectedCenterColorRGB = mask ? color2MaskedRGB : color2RGB;
GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB;
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
if (clearDepth)
// If there is depth, but depth is not asked to be cleared, the depth buffer contains garbage,
// so no particular behavior can be expected.
if (clearDepth || !mHasDepth)
{
// We use a small shader to verify depth.
ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_EQUAL);
drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
glDepthFunc(mask ? GL_GREATER : GL_EQUAL);
// - If depth is cleared, but it's masked, 0.9 should be in the depth buffer.
// - If depth is cleared, but it's not masked, 0.5 should be in the depth buffer.
// - If depth is not cleared, the if above ensures there is no depth buffer at all,
// which means depth test will always pass.
drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), mask ? 1.0f : 0.0f);
glDisable(GL_DEPTH_TEST);
ASSERT_GL_NO_ERROR();
expectedColorRGB = mask ? expectedColorRGB : GLColor::blue;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedColorRGB, 1);
// Either way, we expect blue to be written to the center.
expectedCenterColorRGB = GLColor::blue;
// If there is no depth, depth test always passes so the whole image must be blue. Same if
// depth write is masked.
expectedCornerColorRGB =
mHasDepth && scissor && !mask ? expectedCornerColorRGB : GLColor::blue;
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
}
if (clearStencil)
// If there is stencil, but it's not asked to be cleared, there is similarly no expectation.
if (clearStencil || !mHasStencil)
{
// And another small shader to verify stencil.
ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Green());
glEnable(GL_STENCIL_TEST);
// - If stencil is cleared, but it's masked, 0x59 should be in the stencil buffer.
// - If stencil is cleared, but it's not masked, 0xFF should be in the stencil buffer.
// - If stencil is not cleared, the if above ensures there is no stencil buffer at all,
// which means stencil test will always pass.
glStencilFunc(GL_EQUAL, mask ? 0x59 : 0xFF, 0xFF);
drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
glDisable(GL_STENCIL_TEST);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, GLColor::green, 1);
// Either way, we expect green to be written to the center.
expectedCenterColorRGB = GLColor::green;
// If there is no stencil, stencil test always passes so the whole image must be green.
expectedCornerColorRGB = mHasStencil && scissor ? expectedCornerColorRGB : GLColor::green;
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
}
}
......@@ -709,6 +798,62 @@ TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear)
MaskedScissoredColorDepthStencilClear(true, true, true, true);
}
// Tests combined color+stencil scissored masked clears for a depth-stencil-emulated
// stencil-only-type.
TEST_P(VulkanClearTest, ColorAndStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, false, false, true);
}
TEST_P(VulkanClearTest, MaskedColorAndStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, false, false, true);
}
TEST_P(VulkanClearTest, ScissoredColorAndStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, true, false, true);
}
TEST_P(VulkanClearTest, MaskedScissoredColorAndStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, true, false, true);
}
// Tests combined color+depth scissored masked clears for a depth-stencil-emulated
// depth-only-type.
TEST_P(VulkanClearTest, ColorAndDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, false, true, false);
}
TEST_P(VulkanClearTest, MaskedColorAndDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, false, true, false);
}
TEST_P(VulkanClearTest, ScissoredColorAndDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, true, true, false);
}
TEST_P(VulkanClearTest, MaskedScissoredColorAndDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, true, true, false);
}
// Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an
// assert.
TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert)
......@@ -735,6 +880,7 @@ ANGLE_INSTANTIATE_TEST(ClearTest,
ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(ClearTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ScissoredClearTest, ES2_D3D11(), ES2_OPENGL(), ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(VulkanClearTest, ES2_VULKAN());
// Not all ANGLE backends support RGB backbuffers
ANGLE_INSTANTIATE_TEST(ClearTestRGB, ES2_D3D11(), ES3_D3D11(), ES2_VULKAN());
......
......@@ -79,6 +79,16 @@ void TestPlatform_overrideWorkaroundsD3D(angle::PlatformMethods *platform,
}
}
void TestPlatform_overrideFeaturesVk(angle::PlatformMethods *platform,
FeaturesVk *workaroundsVulkan)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->currentTest)
{
testPlatformContext->currentTest->overrideFeaturesVk(workaroundsVulkan);
}
}
std::array<angle::Vector3, 4> GetIndexedQuadVertices()
{
std::array<angle::Vector3, 4> vertices;
......@@ -350,6 +360,7 @@ void ANGLETestBase::ANGLETestSetUp()
}
mPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D;
mPlatformMethods.overrideFeaturesVk = angle::TestPlatform_overrideFeaturesVk;
mPlatformMethods.logError = angle::TestPlatform_logError;
mPlatformMethods.logWarning = angle::TestPlatform_logWarning;
mPlatformMethods.logInfo = angle::TestPlatform_logInfo;
......
......@@ -118,8 +118,6 @@ static constexpr GLColor32F kFloatRed = {1.0f, 0.0f, 0.0f, 1.0f};
static constexpr GLColor32F kFloatGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static constexpr GLColor32F kFloatBlue = {0.0f, 0.0f, 1.0f, 1.0f};
struct WorkaroundsD3D;
// The input here for pixelPoints are the expected integer window coordinates, we add .5 to every
// one of them and re-scale the numbers to be between [-1,1]. Using this technique, we can make
// sure the rasterization stage will end up drawing pixels at the expected locations.
......@@ -260,6 +258,7 @@ class ANGLETestBase
static bool eglDisplayExtensionEnabled(EGLDisplay display, const std::string &extName);
virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {}
virtual void overrideFeaturesVk(angle::FeaturesVk *workaroundsVulkan) {}
protected:
void ANGLETestSetUp();
......@@ -474,7 +473,6 @@ bool IsRelease();
do \
{ \
if (COND) \
\
{ \
std::cout << "Test skipped: " #COND "." << std::endl; \
return; \
......
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