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 @@ ...@@ -3,14 +3,15 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// vk_helpers: // FeaturesVk.h: Optional features for the Vulkan renderer.
// Optional features for the Vulkan renderer. //
#ifndef LIBANGLE_RENDERER_VULKAN_FEATURESVK_H_ #ifndef ANGLE_PLATFORM_FEATURESVK_H_
#define LIBANGLE_RENDERER_VULKAN_FEATURESVK_H_ #define ANGLE_PLATFORM_FEATURESVK_H_
namespace rx namespace angle
{ {
struct FeaturesVk struct FeaturesVk
{ {
// Line segment rasterization must follow OpenGL rules. This means using an algorithm similar // Line segment rasterization must follow OpenGL rules. This means using an algorithm similar
...@@ -37,7 +38,13 @@ struct FeaturesVk ...@@ -37,7 +38,13 @@ struct FeaturesVk
// Add an extra copy region when using vkCmdCopyBuffer as the Windows Intel driver seems // Add an extra copy region when using vkCmdCopyBuffer as the Windows Intel driver seems
// to have a bug where the last region is ignored. // to have a bug where the last region is ignored.
bool extraCopyBufferRegion = false; 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 @@ ...@@ -36,6 +36,7 @@
namespace angle namespace angle
{ {
struct WorkaroundsD3D; struct WorkaroundsD3D;
struct FeaturesVk;
using TraceEventHandle = uint64_t; using TraceEventHandle = uint64_t;
using EGLDisplayType = void *; using EGLDisplayType = void *;
struct PlatformMethods; struct PlatformMethods;
...@@ -233,6 +234,13 @@ inline void DefaultOverrideWorkaroundsD3D(PlatformMethods *platform, ...@@ -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 // 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. // shaders to disk. Keys are a 160-bit SHA-1 hash.
using ProgramKeyType = std::array<uint8_t, 20>; using ProgramKeyType = std::array<uint8_t, 20>;
...@@ -262,6 +270,7 @@ inline void DefaultCacheProgram(PlatformMethods *platform, ...@@ -262,6 +270,7 @@ inline void DefaultCacheProgram(PlatformMethods *platform,
OP(histogramSparse, HistogramSparse) \ OP(histogramSparse, HistogramSparse) \
OP(histogramBoolean, HistogramBoolean) \ OP(histogramBoolean, HistogramBoolean) \
OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \ OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \
OP(overrideFeaturesVk, OverrideFeaturesVk) \
OP(cacheProgram, CacheProgram) OP(cacheProgram, CacheProgram)
#define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName; #define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName;
......
...@@ -1142,7 +1142,7 @@ VkColorComponentFlags ContextVk::getClearColorMask() const ...@@ -1142,7 +1142,7 @@ VkColorComponentFlags ContextVk::getClearColorMask() const
return mClearColorMask; return mClearColorMask;
} }
const FeaturesVk &ContextVk::getFeatures() const const angle::FeaturesVk &ContextVk::getFeatures() const
{ {
return mRenderer->getFeatures(); return mRenderer->getFeatures();
} }
......
...@@ -16,9 +16,13 @@ ...@@ -16,9 +16,13 @@
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx namespace angle
{ {
struct FeaturesVk; struct FeaturesVk;
}
namespace rx
{
class RendererVk; class RendererVk;
class ContextVk : public ContextImpl, public vk::Context class ContextVk : public ContextImpl, public vk::Context
...@@ -157,7 +161,7 @@ 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; angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
VkDevice getDevice() const; VkDevice getDevice() const;
const FeaturesVk &getFeatures() const; const angle::FeaturesVk &getFeatures() const;
void invalidateVertexAndIndexBuffers(); void invalidateVertexAndIndexBuffers();
void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttribute(size_t attribIndex);
......
...@@ -187,8 +187,36 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -187,8 +187,36 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
bool clearColor = IsMaskFlagSet(static_cast<int>(mask), GL_COLOR_BUFFER_BIT); bool clearColor = IsMaskFlagSet(static_cast<int>(mask), GL_COLOR_BUFFER_BIT);
const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthStencilAttachment(); const gl::State &glState = context->getGLState();
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 // 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 // only be done with a draw call. The scissor region however can easily be integrated with
...@@ -206,24 +234,19 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -206,24 +234,19 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
if (clearDepth || clearStencil) if (clearDepth || clearStencil)
{ {
ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil)); ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil,
clearDepthStencilValue));
} }
return angle::Result::Continue(); return angle::Result::Continue();
} }
// If we clear the depth OR the stencil but not both, and we have a packed depth stencil if (glState.isScissorTestEnabled())
// 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)
{ {
// With scissor test enabled, we clear very differently and we don't need to access // 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 // the image inside each attachment we can just use clearCmdAttachments with our
// scissor region instead. // scissor region instead.
ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil)); ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil,
clearDepthStencilValue));
return angle::Result::Continue(); return angle::Result::Continue();
} }
...@@ -232,19 +255,22 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -232,19 +255,22 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
{ {
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); 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(); RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil();
const angle::Format &format = renderTarget->getImageFormat().textureFormat(); const angle::Format &format = renderTarget->getImageFormat().textureFormat();
const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); 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); vk::ImageHelper *image = renderTarget->getImageForWrite(&mFramebuffer);
image->clearDepthStencil(aspectFlags, clearDepthStencilValue, commandBuffer); image->clearDepthStencil(aspectFlags, clearAspects, clearDepthStencilValue, commandBuffer);
} }
if (!clearColor) if (!clearColor)
...@@ -875,10 +901,12 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe ...@@ -875,10 +901,12 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe
return angle::Result::Continue(); return angle::Result::Continue();
} }
angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, angle::Result FramebufferVk::clearWithClearAttachments(
bool clearColor, ContextVk *contextVk,
bool clearDepth, bool clearColor,
bool clearStencil) bool clearDepth,
bool clearStencil,
const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
// Trigger a new command node to ensure overlapping writes happen sequentially. // Trigger a new command node to ensure overlapping writes happen sequentially.
mFramebuffer.finishCurrentCommands(contextVk->getRenderer()); mFramebuffer.finishCurrentCommands(contextVk->getRenderer());
...@@ -939,15 +967,8 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, ...@@ -939,15 +967,8 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
} }
} }
VkClearValue depthStencilClearValue = contextVk->getClearDepthStencilValue(); VkClearValue depthStencilClearValue = {};
depthStencilClearValue.depthStencil = clearDepthStencilValue;
// 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;
}
if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr) if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr)
{ {
......
...@@ -161,7 +161,8 @@ class FramebufferVk : public FramebufferImpl ...@@ -161,7 +161,8 @@ class FramebufferVk : public FramebufferImpl
angle::Result clearWithClearAttachments(ContextVk *contextVk, angle::Result clearWithClearAttachments(ContextVk *contextVk,
bool clearColor, bool clearColor,
bool clearDepth, bool clearDepth,
bool clearStencil); bool clearStencil,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, VkColorComponentFlags colorMaskFlags); angle::Result clearWithDraw(ContextVk *contextVk, VkColorComponentFlags colorMaskFlags);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a); 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, ...@@ -89,7 +89,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
if (isDepthOrStencilFormat) if (isDepthOrStencilFormat)
{ {
mImage.clearDepthStencil(aspect, kDefaultClearDepthStencilValue, commandBuffer); mImage.clearDepthStencil(aspect, aspect, kDefaultClearDepthStencilValue, commandBuffer);
} }
else else
{ {
......
...@@ -531,7 +531,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, ...@@ -531,7 +531,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
GlslangWrapper::Initialize(); GlslangWrapper::Initialize();
// Initialize the format table. // Initialize the format table.
mFormatTable.initialize(mPhysicalDevice, &mNativeTextureCaps, mFormatTable.initialize(mPhysicalDevice, mFeatures, &mNativeTextureCaps,
&mNativeCaps.compressedTextureFormats); &mNativeCaps.compressedTextureFormats);
return angle::Result::Continue(); return angle::Result::Continue();
...@@ -751,6 +751,9 @@ void RendererVk::initFeatures() ...@@ -751,6 +751,9 @@ void RendererVk::initFeatures()
// http://anglebug.com/2838 // http://anglebug.com/2838
mFeatures.extraCopyBufferRegion = IsIntel(mPhysicalDeviceProperties.vendorID); mFeatures.extraCopyBufferRegion = IsIntel(mPhysicalDeviceProperties.vendorID);
#endif #endif
angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesVk(platform, &mFeatures);
} }
void RendererVk::initPipelineCacheVkKey() void RendererVk::initPipelineCacheVkKey()
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "libANGLE/BlobCache.h" #include "libANGLE/BlobCache.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h" #include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/FeaturesVk.h"
#include "libANGLE/renderer/vulkan/QueryVk.h" #include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
...@@ -171,7 +170,7 @@ class RendererVk : angle::NonCopyable ...@@ -171,7 +170,7 @@ class RendererVk : angle::NonCopyable
Serial issueShaderSerial(); Serial issueShaderSerial();
vk::ShaderLibrary *getShaderLibrary(); 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); angle::Result getTimestamp(vk::Context *context, uint64_t *timestampOut);
...@@ -226,7 +225,7 @@ class RendererVk : angle::NonCopyable ...@@ -226,7 +225,7 @@ class RendererVk : angle::NonCopyable
mutable gl::TextureCapsMap mNativeTextureCaps; mutable gl::TextureCapsMap mNativeTextureCaps;
mutable gl::Extensions mNativeExtensions; mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations; mutable gl::Limitations mNativeLimitations;
mutable FeaturesVk mFeatures; mutable angle::FeaturesVk mFeatures;
VkInstance mInstance; VkInstance mInstance;
bool mEnableValidationLayers; bool mEnableValidationLayers;
......
...@@ -529,7 +529,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) ...@@ -529,7 +529,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
// Clear the image. // Clear the image.
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mDepthStencilImage.recordCommands(displayVk, &commandBuffer)); 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, ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect,
gl::SwizzleState(), &mDepthStencilImageView, 1)); gl::SwizzleState(), &mDepthStencilImageView, 1));
......
...@@ -41,7 +41,9 @@ namespace rx ...@@ -41,7 +41,9 @@ namespace rx
namespace vk 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) switch (angleFormat.id)
{{ {{
...@@ -77,7 +79,7 @@ texture_struct_template="{{{texture}, {vk_texture_format}, {texture_initializer} ...@@ -77,7 +79,7 @@ texture_struct_template="{{{texture}, {vk_texture_format}, {texture_initializer}
texture_fallback_template = """{{ texture_fallback_template = """{{
static constexpr TextureFormatInitInfo kInfo[] = {{{texture_list}}}; static constexpr TextureFormatInitInfo kInfo[] = {{{texture_list}}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo)); initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
}}""" }}"""
buffer_basic_template = """bufferFormatID = {buffer}; buffer_basic_template = """bufferFormatID = {buffer};
...@@ -95,67 +97,72 @@ initBufferFallback(physicalDevice, kInfo, ArraySize(kInfo)); ...@@ -95,67 +97,72 @@ initBufferFallback(physicalDevice, kInfo, ArraySize(kInfo));
}}""" }}"""
def is_packed(format_id): def is_packed(format_id):
return "true" if "_PACK" in format_id else "false" return "true" if "_PACK" in format_id else "false"
def gen_format_case(angle, internal_format, vk_json_data): def gen_format_case(angle, internal_format, vk_json_data):
vk_map = vk_json_data["map"] vk_map = vk_json_data["map"]
vk_overrides = vk_json_data["overrides"] vk_overrides = vk_json_data["overrides"]
vk_fallbacks = vk_json_data["fallbacks"] vk_fallbacks = vk_json_data["fallbacks"]
args = dict(format_id=angle, internal_format=internal_format, args = dict(
texture_template="", buffer_template="") format_id=angle,
internal_format=internal_format,
if ((angle not in vk_map) and (angle not in vk_overrides) and texture_template="",
(angle not in vk_fallbacks)) or angle == 'NONE': buffer_template="")
return empty_format_entry_template.format(**args)
if ((angle not in vk_map) and (angle not in vk_overrides) and
def get_formats(format, type): (angle not in vk_fallbacks)) or angle == 'NONE':
format = vk_overrides.get(format, {}).get(type, format) return empty_format_entry_template.format(**args)
if format not in vk_map:
return [] def get_formats(format, type):
fallbacks = vk_fallbacks.get(format, {}).get(type, []) format = vk_overrides.get(format, {}).get(type, format)
if not isinstance(fallbacks, list): if format not in vk_map:
fallbacks = [fallbacks] return []
return [format] + fallbacks fallbacks = vk_fallbacks.get(format, {}).get(type, [])
if not isinstance(fallbacks, list):
def texture_args(format): fallbacks = [fallbacks]
return dict( return [format] + fallbacks
texture="angle::FormatID::" + format,
vk_texture_format=vk_map[format], def texture_args(format):
texture_initializer=angle_format.get_internal_format_initializer(internal_format, return dict(
format) texture="angle::FormatID::" + format,
) vk_texture_format=vk_map[format],
texture_initializer=angle_format.get_internal_format_initializer(
def buffer_args(format): internal_format, format))
return dict(
buffer="angle::FormatID::" + format, def buffer_args(format):
vk_buffer_format=vk_map[format], return dict(
vk_buffer_format_is_packed=is_packed(vk_map[format]), buffer="angle::FormatID::" + format,
vertex_load_function=angle_format.get_vertex_copy_function(angle, format), vk_buffer_format=vk_map[format],
vertex_load_converts='false' if angle == format else 'true', vk_buffer_format_is_packed=is_packed(vk_map[format]),
) vertex_load_function=angle_format.get_vertex_copy_function(
angle, format),
textures = get_formats(angle, "texture") vertex_load_converts='false' if angle == format else 'true',
if len(textures) == 1: )
args.update(texture_template=texture_basic_template)
args.update(texture_args(textures[0])) textures = get_formats(angle, "texture")
elif len(textures) > 1: if len(textures) == 1:
args.update( args.update(texture_template=texture_basic_template)
texture_template=texture_fallback_template, args.update(texture_args(textures[0]))
texture_list=", ".join(texture_struct_template.format(**texture_args(i)) elif len(textures) > 1:
for i in textures) args.update(
) texture_template=texture_fallback_template,
texture_list=", ".join(
buffers = get_formats(angle, "buffer") texture_struct_template.format(**texture_args(i))
if len(buffers) == 1: for i in textures))
args.update(buffer_template=buffer_basic_template)
args.update(buffer_args(buffers[0])) buffers = get_formats(angle, "buffer")
elif len(buffers) > 1: if len(buffers) == 1:
args.update( args.update(buffer_template=buffer_basic_template)
buffer_template=buffer_fallback_template, args.update(buffer_args(buffers[0]))
buffer_list=", ".join(buffer_struct_template.format(**buffer_args(i)) for i in buffers) elif len(buffers) > 1:
) args.update(
buffer_template=buffer_fallback_template,
return format_entry_template.format(**args).format(**args) 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' input_file_name = 'vk_format_map.json'
out_file_name = 'vk_format_table' out_file_name = 'vk_format_table'
...@@ -173,5 +180,5 @@ output_cpp = template_table_autogen_cpp.format( ...@@ -173,5 +180,5 @@ output_cpp = template_table_autogen_cpp.format(
input_file_name = input_file_name) input_file_name = input_file_name)
with open(out_file_name + '_autogen.cpp', 'wt') as out_file: with open(out_file_name + '_autogen.cpp', 'wt') as out_file:
out_file.write(output_cpp) out_file.write(output_cpp)
out_file.close() out_file.close()
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h" #include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FeaturesVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "vk_format_utils.h" #include "vk_format_utils.h"
......
...@@ -243,16 +243,16 @@ ...@@ -243,16 +243,16 @@
}, },
"fallbacks": { "fallbacks": {
"D32_FLOAT_S8X24_UINT": { "D32_FLOAT_S8X24_UINT": {
"texture": "D24_UNORM_S8_UINT" "texture": ["D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT"]
}, },
"D24_UNORM_S8_UINT": { "D24_UNORM_S8_UINT": {
"texture": "D32_FLOAT_S8X24_UINT" "texture": ["D32_FLOAT_S8X24_UINT", "D24_UNORM_S8_UINT"]
}, },
"D24_UNORM_X8_UINT": { "D24_UNORM_X8_UINT": {
"texture": "D32_FLOAT_S8X24_UINT" "texture": ["D32_FLOAT_S8X24_UINT", "D24_UNORM_S8_UINT"]
}, },
"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": { "R8_UNORM": {
...@@ -352,6 +352,5 @@ ...@@ -352,6 +352,5 @@
"R16G16B16A16_SSCALED": { "R16G16B16A16_SSCALED": {
"buffer": "R32G32B32A32_FLOAT" "buffer": "R32G32B32A32_FLOAT"
} }
} }
} }
...@@ -22,7 +22,9 @@ namespace rx ...@@ -22,7 +22,9 @@ namespace rx
namespace vk 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) switch (angleFormat.id)
{ {
...@@ -535,8 +537,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an ...@@ -535,8 +537,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{ {
static constexpr TextureFormatInitInfo kInfo[] = { static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_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}}; {angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo)); {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; bufferFormatID = angle::FormatID::D24_UNORM_S8_UINT;
vkBufferFormat = VK_FORMAT_D24_UNORM_S8_UINT; vkBufferFormat = VK_FORMAT_D24_UNORM_S8_UINT;
...@@ -550,8 +553,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an ...@@ -550,8 +553,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{ {
static constexpr TextureFormatInitInfo kInfo[] = { static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_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}}; {angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo)); {angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
} }
bufferFormatID = angle::FormatID::NONE; bufferFormatID = angle::FormatID::NONE;
vkBufferFormat = VK_FORMAT_UNDEFINED; vkBufferFormat = VK_FORMAT_UNDEFINED;
...@@ -577,8 +581,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an ...@@ -577,8 +581,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
{ {
static constexpr TextureFormatInitInfo kInfo[] = { static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr}, {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}}; {angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, nullptr},
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo)); {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; bufferFormatID = angle::FormatID::D32_FLOAT_S8X24_UINT;
vkBufferFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; vkBufferFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;
...@@ -666,7 +671,7 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an ...@@ -666,7 +671,7 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
textureInitializerFunction = Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>; textureInitializerFunction = Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>;
bufferFormatID = angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK; bufferFormatID = angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK;
vkBufferFormat = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; vkBufferFormat = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
vkBufferFormatIsPacked = false; vkBufferFormatIsPacked = false;
vertexLoadFunction = CopyNativeVertexData<GLubyte, 4, 4, 0>; vertexLoadFunction = CopyNativeVertexData<GLubyte, 4, 4, 0>;
vertexLoadRequiresConversion = false; vertexLoadRequiresConversion = false;
break; break;
...@@ -1813,8 +1818,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an ...@@ -1813,8 +1818,9 @@ void Format::initialize(VkPhysicalDevice physicalDevice, const angle::Format &an
static constexpr TextureFormatInitInfo kInfo[] = { static constexpr TextureFormatInitInfo kInfo[] = {
{angle::FormatID::S8_UINT, VK_FORMAT_S8_UINT, nullptr}, {angle::FormatID::S8_UINT, VK_FORMAT_S8_UINT, nullptr},
{angle::FormatID::D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_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}}; {angle::FormatID::D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, nullptr},
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo)); {angle::FormatID::S8_UINT, VK_FORMAT_S8_UINT, nullptr}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
} }
bufferFormatID = angle::FormatID::S8_UINT; bufferFormatID = angle::FormatID::S8_UINT;
vkBufferFormat = VK_FORMAT_S8_UINT; vkBufferFormat = VK_FORMAT_S8_UINT;
......
...@@ -71,7 +71,7 @@ int FindSupportedFormat(VkPhysicalDevice physicalDevice, ...@@ -71,7 +71,7 @@ int FindSupportedFormat(VkPhysicalDevice physicalDevice,
int numInfo, int numInfo,
SupportTest hasSupport) SupportTest hasSupport)
{ {
ASSERT(numInfo > 1); ASSERT(numInfo > 0);
const int last = numInfo - 1; const int last = numInfo - 1;
for (int i = 0; i < last; ++i) for (int i = 0; i < last; ++i)
...@@ -131,9 +131,14 @@ Format::Format() ...@@ -131,9 +131,14 @@ Format::Format()
void Format::initTextureFallback(VkPhysicalDevice physicalDevice, void Format::initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info, 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; textureFormatID = info[i].format;
vkTextureFormat = info[i].vkFormat; vkTextureFormat = info[i].vkFormat;
textureInitializerFunction = info[i].initializer; textureInitializerFunction = info[i].initializer;
...@@ -186,6 +191,7 @@ FormatTable::~FormatTable() ...@@ -186,6 +191,7 @@ FormatTable::~FormatTable()
} }
void FormatTable::initialize(VkPhysicalDevice physicalDevice, void FormatTable::initialize(VkPhysicalDevice physicalDevice,
const angle::FeaturesVk &featuresVk,
gl::TextureCapsMap *outTextureCapsMap, gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats) std::vector<GLenum> *outCompressedTextureFormats)
{ {
...@@ -193,7 +199,7 @@ void FormatTable::initialize(VkPhysicalDevice physicalDevice, ...@@ -193,7 +199,7 @@ void FormatTable::initialize(VkPhysicalDevice physicalDevice,
{ {
const auto formatID = static_cast<angle::FormatID>(formatIndex); const auto formatID = static_cast<angle::FormatID>(formatIndex);
const angle::Format &angleFormat = angle::Format::Get(formatID); 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; const GLenum internalFormat = mFormatData[formatIndex].internalFormat;
mFormatData[formatIndex].textureLoadFunctions = mFormatData[formatIndex].textureLoadFunctions =
GetLoadFunctionsMap(internalFormat, mFormatData[formatIndex].textureFormatID); GetLoadFunctionsMap(internalFormat, mFormatData[formatIndex].textureFormatID);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "libANGLE/renderer/Format.h" #include "libANGLE/renderer/Format.h"
#include "libANGLE/renderer/copyvertex.h" #include "libANGLE/renderer/copyvertex.h"
#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/renderer_utils.h"
#include "platform/FeaturesVk.h"
#include <array> #include <array>
...@@ -56,11 +57,14 @@ struct Format final : private angle::NonCopyable ...@@ -56,11 +57,14 @@ struct Format final : private angle::NonCopyable
bool valid() const { return internalFormat != 0; } bool valid() const { return internalFormat != 0; }
// This is an auto-generated method in vk_format_table_autogen.cpp. // 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, void initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info, const TextureFormatInitInfo *info,
int numInfo); int numInfo,
const angle::FeaturesVk &featuresVk);
void initBufferFallback(VkPhysicalDevice physicalDevice, void initBufferFallback(VkPhysicalDevice physicalDevice,
const BufferFormatInitInfo *info, const BufferFormatInitInfo *info,
int numInfo); int numInfo);
...@@ -93,6 +97,7 @@ class FormatTable final : angle::NonCopyable ...@@ -93,6 +97,7 @@ class FormatTable final : angle::NonCopyable
// Also initializes the TextureCapsMap and the compressedTextureCaps in the Caps instance. // Also initializes the TextureCapsMap and the compressedTextureCaps in the Caps instance.
void initialize(VkPhysicalDevice physicalDevice, void initialize(VkPhysicalDevice physicalDevice,
const angle::FeaturesVk &featuresVk,
gl::TextureCapsMap *outTextureCapsMap, gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats); std::vector<GLenum> *outCompressedTextureFormats);
......
...@@ -1238,18 +1238,19 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color, ...@@ -1238,18 +1238,19 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color,
commandBuffer->clearColorImage(mImage, mCurrentLayout, color, 1, &range); commandBuffer->clearColorImage(mImage, mCurrentLayout, color, 1, &range);
} }
void ImageHelper::clearDepthStencil(VkImageAspectFlags aspectFlags, void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil, const VkClearDepthStencilValue &depthStencil,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
ASSERT(valid()); 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, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer); commandBuffer);
VkImageSubresourceRange clearRange = { VkImageSubresourceRange clearRange = {
/*aspectMask*/ aspectFlags, /*aspectMask*/ clearAspectFlags,
/*baseMipLevel*/ 0, /*baseMipLevel*/ 0,
/*levelCount*/ 1, /*levelCount*/ 1,
/*baseArrayLayer*/ 0, /*baseArrayLayer*/ 0,
......
...@@ -471,7 +471,8 @@ class ImageHelper final : public RecordableGraphResource ...@@ -471,7 +471,8 @@ class ImageHelper final : public RecordableGraphResource
uint32_t layerCount, uint32_t layerCount,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
void clearDepthStencil(VkImageAspectFlags aspectFlags, void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil, const VkClearDepthStencilValue &depthStencil,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
gl::Extents getSize(const gl::ImageIndex &index) const; gl::Extents getSize(const gl::ImageIndex &index) const;
......
...@@ -108,6 +108,7 @@ libangle_includes = [ ...@@ -108,6 +108,7 @@ libangle_includes = [
"include/GLSLANG/ShaderLang.h", "include/GLSLANG/ShaderLang.h",
"include/GLSLANG/ShaderVars.h", "include/GLSLANG/ShaderVars.h",
"include/KHR/khrplatform.h", "include/KHR/khrplatform.h",
"include/platform/FeaturesVk.h",
"include/platform/Platform.h", "include/platform/Platform.h",
"include/platform/WorkaroundsD3D.h", "include/platform/WorkaroundsD3D.h",
] ]
...@@ -747,7 +748,6 @@ libangle_vulkan_sources = [ ...@@ -747,7 +748,6 @@ libangle_vulkan_sources = [
"src/libANGLE/renderer/vulkan/DeviceVk.h", "src/libANGLE/renderer/vulkan/DeviceVk.h",
"src/libANGLE/renderer/vulkan/DisplayVk.cpp", "src/libANGLE/renderer/vulkan/DisplayVk.cpp",
"src/libANGLE/renderer/vulkan/DisplayVk.h", "src/libANGLE/renderer/vulkan/DisplayVk.h",
"src/libANGLE/renderer/vulkan/FeaturesVk.h",
"src/libANGLE/renderer/vulkan/FenceNVVk.cpp", "src/libANGLE/renderer/vulkan/FenceNVVk.cpp",
"src/libANGLE/renderer/vulkan/FenceNVVk.h", "src/libANGLE/renderer/vulkan/FenceNVVk.h",
"src/libANGLE/renderer/vulkan/FramebufferVk.cpp", "src/libANGLE/renderer/vulkan/FramebufferVk.cpp",
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "platform/FeaturesVk.h"
#include "random_utils.h" #include "random_utils.h"
#include "shader_utils.h" #include "shader_utils.h"
#include "test_utils/gl_raii.h" #include "test_utils/gl_raii.h"
...@@ -85,6 +86,9 @@ class ClearTest : public ClearTestBase ...@@ -85,6 +86,9 @@ class ClearTest : public ClearTestBase
bool scissor, bool scissor,
bool clearDepth, bool clearDepth,
bool clearStencil); bool clearStencil);
bool mHasDepth = true;
bool mHasStencil = true;
}; };
class ClearTestES3 : public ClearTestBase class ClearTestES3 : public ClearTestBase
...@@ -108,6 +112,77 @@ class ScissoredClearTest : public ClearTest ...@@ -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 clearing the default framebuffer
TEST_P(ClearTest, DefaultFramebuffer) TEST_P(ClearTest, DefaultFramebuffer)
{ {
...@@ -546,12 +621,12 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -546,12 +621,12 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
const int whalf = w >> 1; const int whalf = w >> 1;
const int hhalf = h >> 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); Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f);
GLColor color1RGB(color1); GLColor color1RGB(color1);
glClearColor(color1[0], color1[1], color1[2], color1[3]); glClearColor(color1[0], color1[1], color1[2], color1[3]);
glClearDepthf(1.0f); glClearDepthf(0.9f);
glClearStencil(0x00); glClearStencil(0x00);
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); (clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
...@@ -583,69 +658,83 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -583,69 +658,83 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glStencilMask(0xFF); glStencilMask(0xFF);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify second clear mask worked as expected. // Verify second clear mask worked as expected.
GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]); 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(whalf, hhalf, expectedCenterColorRGB, 1);
{
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);
}
glDisable(GL_DEPTH_TEST); EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
glDisable(GL_STENCIL_TEST); EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
glDisable(GL_SCISSOR_TEST); 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. // We use a small shader to verify depth.
ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(), ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Blue()); essl1_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_EQUAL); glDepthFunc(mask ? GL_GREATER : GL_EQUAL);
drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), 0.0f); // - 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); glDisable(GL_DEPTH_TEST);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
expectedColorRGB = mask ? expectedColorRGB : GLColor::blue; // Either way, we expect blue to be written to the center.
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedColorRGB, 1); 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(whalf, hhalf, expectedCenterColorRGB, 1);
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 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. // And another small shader to verify stencil.
ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(), ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Green()); essl1_shaders::fs::Green());
glEnable(GL_STENCIL_TEST); 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); glStencilFunc(GL_EQUAL, mask ? 0x59 : 0xFF, 0xFF);
drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f); drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
ASSERT_GL_NO_ERROR(); 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(whalf, hhalf, expectedCenterColorRGB, 1);
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
}
} }
} }
...@@ -709,6 +798,62 @@ TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear) ...@@ -709,6 +798,62 @@ TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear)
MaskedScissoredColorDepthStencilClear(true, true, true, true); 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 // Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an
// assert. // assert.
TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert) TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert)
...@@ -735,6 +880,7 @@ ANGLE_INSTANTIATE_TEST(ClearTest, ...@@ -735,6 +880,7 @@ ANGLE_INSTANTIATE_TEST(ClearTest,
ES2_VULKAN()); ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(ClearTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(ClearTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ScissoredClearTest, ES2_D3D11(), ES2_OPENGL(), ES2_VULKAN()); ANGLE_INSTANTIATE_TEST(ScissoredClearTest, ES2_D3D11(), ES2_OPENGL(), ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(VulkanClearTest, ES2_VULKAN());
// Not all ANGLE backends support RGB backbuffers // Not all ANGLE backends support RGB backbuffers
ANGLE_INSTANTIATE_TEST(ClearTestRGB, ES2_D3D11(), ES3_D3D11(), ES2_VULKAN()); ANGLE_INSTANTIATE_TEST(ClearTestRGB, ES2_D3D11(), ES3_D3D11(), ES2_VULKAN());
......
...@@ -79,6 +79,16 @@ void TestPlatform_overrideWorkaroundsD3D(angle::PlatformMethods *platform, ...@@ -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> GetIndexedQuadVertices()
{ {
std::array<angle::Vector3, 4> vertices; std::array<angle::Vector3, 4> vertices;
...@@ -350,6 +360,7 @@ void ANGLETestBase::ANGLETestSetUp() ...@@ -350,6 +360,7 @@ void ANGLETestBase::ANGLETestSetUp()
} }
mPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D; mPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D;
mPlatformMethods.overrideFeaturesVk = angle::TestPlatform_overrideFeaturesVk;
mPlatformMethods.logError = angle::TestPlatform_logError; mPlatformMethods.logError = angle::TestPlatform_logError;
mPlatformMethods.logWarning = angle::TestPlatform_logWarning; mPlatformMethods.logWarning = angle::TestPlatform_logWarning;
mPlatformMethods.logInfo = angle::TestPlatform_logInfo; mPlatformMethods.logInfo = angle::TestPlatform_logInfo;
......
...@@ -118,8 +118,6 @@ static constexpr GLColor32F kFloatRed = {1.0f, 0.0f, 0.0f, 1.0f}; ...@@ -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 kFloatGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static constexpr GLColor32F kFloatBlue = {0.0f, 0.0f, 1.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 // 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 // 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. // sure the rasterization stage will end up drawing pixels at the expected locations.
...@@ -260,6 +258,7 @@ class ANGLETestBase ...@@ -260,6 +258,7 @@ class ANGLETestBase
static bool eglDisplayExtensionEnabled(EGLDisplay display, const std::string &extName); static bool eglDisplayExtensionEnabled(EGLDisplay display, const std::string &extName);
virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {} virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {}
virtual void overrideFeaturesVk(angle::FeaturesVk *workaroundsVulkan) {}
protected: protected:
void ANGLETestSetUp(); void ANGLETestSetUp();
...@@ -474,7 +473,6 @@ bool IsRelease(); ...@@ -474,7 +473,6 @@ bool IsRelease();
do \ do \
{ \ { \
if (COND) \ if (COND) \
\
{ \ { \
std::cout << "Test skipped: " #COND "." << std::endl; \ std::cout << "Test skipped: " #COND "." << std::endl; \
return; \ 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