Commit 93560ef5 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Seamful cube map emulation

In GLSL, a cube texture is sampled with one of textureCube* functions. This function takes a 3D coordinate which is a vector from the center of the cube and identifies a direction to sample from. GLES2.0 has the following table that translates this 3D coordinate (Rx, Ry, Rz) to a face and ST coordinates within that face. This table can be found in Section 3.7.5 (Cube Map Texture Selection). A compiler pass is implemented in ANGLE that replaces samplerCube declarations with a sampler2DArray. The textureCube* functions are replaced with the corresponding texture* functions with the translated coordinates according to that table. Gradients provided to textureCubeGrad are translated using the same formulae, which is not precise but the spec specifies this projection to be implementation dependent. Helper invocations enabled through WQM (whole quad mode) cause a nuisance in that the extrapolated varyings used as coordinates in a textureCube call could have a different major axis (and therefore face) from the non-helper invocations that lie within the geometry. subgroupQuadSwap* operations are used in conjunction with gl_HelperInvocation to make sure the helper threads calculate texture UVs in the same face as the non-helper invocations. Bug: angleproject:3300 Bug: angleproject:3240 Bug: angleproject:3243 Bug: angleproject:3732 Change-Id: I0cb6a9b1f2e1e6a392b5baca1c7118ed1c502ccf Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1715977Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 44f518b5
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 210 #define ANGLE_SH_VERSION 211
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -287,6 +287,11 @@ const ShCompileOptions SH_FORCE_ATOMIC_VALUE_RESOLUTION = UINT64_C(1) << 42; ...@@ -287,6 +287,11 @@ const ShCompileOptions SH_FORCE_ATOMIC_VALUE_RESOLUTION = UINT64_C(1) << 42;
// Rewrite gl_BaseVertex and gl_BaseInstance as uniform int // Rewrite gl_BaseVertex and gl_BaseInstance as uniform int
const ShCompileOptions SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE = UINT64_C(1) << 43; const ShCompileOptions SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE = UINT64_C(1) << 43;
// Emulate seamful cube map sampling for OpenGL ES2.0. Currently only applies to the Vulkan
// backend, as subgroup operations are used. Once that dependency is broken, could be used with
// the other backends as well.
const ShCompileOptions SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING = UINT64_C(1) << 44;
// Defines alternate strategies for implementing array index clamping. // Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy enum ShArrayIndexClampingStrategy
{ {
......
...@@ -194,6 +194,12 @@ struct FeaturesVk : FeatureSetBase ...@@ -194,6 +194,12 @@ struct FeaturesVk : FeatureSetBase
"On Pixel2, keep using transient vkCommandBuffer to work around driver issue in reseting" "On Pixel2, keep using transient vkCommandBuffer to work around driver issue in reseting"
"vkCommandBuffer", "vkCommandBuffer",
&members, "http://b/135763283"}; &members, "http://b/135763283"};
// Seamful cube map emulation misbehaves on the AMD windows driver, so it's disallowed.
Feature disallowSeamfulCubeMapEmulation = {
"disallow_seamful_cube_map_emulation", FeatureCategory::VulkanWorkarounds,
"Seamful cube map emulation misbehaves on the AMD windows driver, so it's disallowed",
&members, "http://anglebug.com/3243"};
}; };
inline FeaturesVk::FeaturesVk() = default; inline FeaturesVk::FeaturesVk() = default;
......
...@@ -422,6 +422,20 @@ bool IsSamplerType(GLenum type) ...@@ -422,6 +422,20 @@ bool IsSamplerType(GLenum type)
return false; return false;
} }
bool IsSamplerCubeType(GLenum type)
{
switch (type)
{
case GL_SAMPLER_CUBE:
case GL_INT_SAMPLER_CUBE:
case GL_UNSIGNED_INT_SAMPLER_CUBE:
case GL_SAMPLER_CUBE_SHADOW:
return true;
}
return false;
}
bool IsImageType(GLenum type) bool IsImageType(GLenum type)
{ {
switch (type) switch (type)
......
...@@ -38,6 +38,7 @@ size_t VariableExternalSize(GLenum type); ...@@ -38,6 +38,7 @@ size_t VariableExternalSize(GLenum type);
int VariableRowCount(GLenum type); int VariableRowCount(GLenum type);
int VariableColumnCount(GLenum type); int VariableColumnCount(GLenum type);
bool IsSamplerType(GLenum type); bool IsSamplerType(GLenum type);
bool IsSamplerCubeType(GLenum type);
bool IsImageType(GLenum type); bool IsImageType(GLenum type);
bool IsImage2DType(GLenum type); bool IsImage2DType(GLenum type);
bool IsAtomicCounterType(GLenum type); bool IsAtomicCounterType(GLenum type);
......
...@@ -156,6 +156,8 @@ angle_translator_sources = [ ...@@ -156,6 +156,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/RewriteAtomicCounters.h", "src/compiler/translator/tree_ops/RewriteAtomicCounters.h",
"src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp", "src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp",
"src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h", "src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h",
"src/compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.cpp",
"src/compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h",
"src/compiler/translator/tree_ops/RewriteDfdy.cpp", "src/compiler/translator/tree_ops/RewriteDfdy.cpp",
"src/compiler/translator/tree_ops/RewriteDfdy.h", "src/compiler/translator/tree_ops/RewriteDfdy.h",
"src/compiler/translator/tree_ops/RewriteDoWhile.cpp", "src/compiler/translator/tree_ops/RewriteDoWhile.cpp",
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "compiler/translator/StaticType.h" #include "compiler/translator/StaticType.h"
#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h" #include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
#include "compiler/translator/tree_ops/RewriteAtomicCounters.h" #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
#include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
#include "compiler/translator/tree_ops/RewriteDfdy.h" #include "compiler/translator/tree_ops/RewriteDfdy.h"
#include "compiler/translator/tree_ops/RewriteStructSamplers.h" #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
#include "compiler/translator/tree_util/BuiltIn_autogen.h" #include "compiler/translator/tree_util/BuiltIn_autogen.h"
...@@ -644,6 +645,11 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -644,6 +645,11 @@ void TranslatorVulkan::translate(TIntermBlock *root,
sink << "#version 450 core\n"; sink << "#version 450 core\n";
if (compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING)
{
sink << "#extension GL_KHR_shader_subgroup_quad : require\n";
}
// Write out default uniforms into a uniform block assigned to a specific set/binding. // Write out default uniforms into a uniform block assigned to a specific set/binding.
int defaultUniformCount = 0; int defaultUniformCount = 0;
int structTypesUsedForUniforms = 0; int structTypesUsedForUniforms = 0;
...@@ -680,6 +686,14 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -680,6 +686,14 @@ void TranslatorVulkan::translate(TIntermBlock *root,
structTypesTraverser.updateTree(); structTypesTraverser.updateTree();
} }
// Rewrite samplerCubes as sampler2DArrays. This must be done after rewriting struct samplers
// as it doesn't expect that.
if (compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING)
{
RewriteCubeMapSamplersAs2DArray(root, &getSymbolTable(),
getShaderType() == GL_FRAGMENT_SHADER);
}
if (defaultUniformCount > 0) if (defaultUniformCount > 0)
{ {
sink << "\n@@ LAYOUT-defaultUniforms(std140) @@ uniform defaultUniforms\n{\n"; sink << "\n@@ LAYOUT-defaultUniforms(std140) @@ uniform defaultUniforms\n{\n";
......
...@@ -329,6 +329,7 @@ class TType ...@@ -329,6 +329,7 @@ class TType
void realize(); void realize();
bool isSampler() const { return IsSampler(type); } bool isSampler() const { return IsSampler(type); }
bool isSamplerCube() const { return type == EbtSamplerCube; }
bool isAtomicCounter() const { return IsAtomicCounter(type); } bool isAtomicCounter() const { return IsAtomicCounter(type); }
private: private:
......
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RewriteCubeMapSamplersAs2DArray: Change samplerCube samplers to sampler2DArray, and the
// textureCube* function calls to calls to helper functions that select the cube map face and sample
// from the face as a 2D texture. This emulates seamful cube map sampling in ES2 (or desktop GL 2)
// and therefore only looks at samplerCube (i.e. not integer variants or cube arrays) and sampling
// functions that are defined in ES GLSL 1.0 (i.e. not the cube overload of texture()).
#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITECUBEMAPSAMPLERSAS2DARRAY_H_
#define COMPILER_TRANSLATOR_TREEOPS_REWRITECUBEMAPSAMPLERSAS2DARRAY_H_
namespace sh
{
class TIntermBlock;
class TSymbolTable;
void RewriteCubeMapSamplersAs2DArray(TIntermBlock *root,
TSymbolTable *symbolTable,
bool isFragmentShader);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITECUBEMAPSAMPLERSAS2DARRAY_H_
...@@ -438,6 +438,8 @@ angle::Result ContextVk::initialize() ...@@ -438,6 +438,8 @@ angle::Result ContextVk::initialize()
ANGLE_TRY(synchronizeCpuGpuTime()); ANGLE_TRY(synchronizeCpuGpuTime());
} }
mEmulateSeamfulCubeMapSampling = shouldEmulateSeamfulCubeMapSampling();
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2890,4 +2892,30 @@ vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc( ...@@ -2890,4 +2892,30 @@ vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc(
desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, shaderStages); desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, shaderStages);
return desc; return desc;
} }
bool ContextVk::shouldEmulateSeamfulCubeMapSampling() const
{
if (mState.getClientMajorVersion() != 2)
{
return false;
}
if (mRenderer->getFeatures().disallowSeamfulCubeMapEmulation.enabled)
{
return false;
}
constexpr VkSubgroupFeatureFlags kSeamfulCubeMapSubgroupOperations =
VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT |
VK_SUBGROUP_FEATURE_QUAD_BIT;
const VkSubgroupFeatureFlags deviceSupportedOperations =
mRenderer->getPhysicalDeviceSubgroupProperties().supportedOperations;
bool hasSeamfulCubeMapSubgroupOperations =
(deviceSupportedOperations & kSeamfulCubeMapSubgroupOperations) ==
kSeamfulCubeMapSubgroupOperations;
// Only enable seamful cube map emulation if the necessary subgroup operations are supported.
// Without them, we cannot remove derivative-related artifacts caused by helper invocations.
return hasSeamfulCubeMapSubgroupOperations;
}
} // namespace rx } // namespace rx
...@@ -313,6 +313,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -313,6 +313,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void updateScissor(const gl::State &glState); void updateScissor(const gl::State &glState);
bool emulateSeamfulCubeMapSampling() const { return mEmulateSeamfulCubeMapSampling; }
private: private:
// Dirty bits. // Dirty bits.
enum DirtyBitType : size_t enum DirtyBitType : size_t
...@@ -470,6 +472,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -470,6 +472,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void waitForSwapchainImageIfNecessary(); void waitForSwapchainImageIfNecessary();
bool shouldEmulateSeamfulCubeMapSampling() const;
vk::PipelineHelper *mCurrentGraphicsPipeline; vk::PipelineHelper *mCurrentGraphicsPipeline;
vk::PipelineAndSerial *mCurrentComputePipeline; vk::PipelineAndSerial *mCurrentComputePipeline;
gl::PrimitiveMode mCurrentDrawMode; gl::PrimitiveMode mCurrentDrawMode;
...@@ -531,6 +535,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -531,6 +535,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// at the end of the command buffer to make that write available to the host. // at the end of the command buffer to make that write available to the host.
bool mIsAnyHostVisibleBufferWritten; bool mIsAnyHostVisibleBufferWritten;
// Whether this context should do seamful cube map sampling emulation.
bool mEmulateSeamfulCubeMapSampling;
struct DriverUniformsDescriptorSet struct DriverUniformsDescriptorSet
{ {
vk::DynamicBuffer dynamicBuffer; vk::DynamicBuffer dynamicBuffer;
......
...@@ -28,6 +28,7 @@ ANGLE_REENABLE_EXTRA_SEMI_WARNING ...@@ -28,6 +28,7 @@ ANGLE_REENABLE_EXTRA_SEMI_WARNING
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h" #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx namespace rx
...@@ -935,6 +936,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -935,6 +936,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
angle::Result GlslangWrapper::GetShaderCode(vk::Context *context, angle::Result GlslangWrapper::GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation, bool enableLineRasterEmulation,
bool enableSeamfulCubeMapEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{ {
...@@ -954,17 +956,20 @@ angle::Result GlslangWrapper::GetShaderCode(vk::Context *context, ...@@ -954,17 +956,20 @@ angle::Result GlslangWrapper::GetShaderCode(vk::Context *context,
kVersionDefine, kLineRasterDefine), kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV); VK_ERROR_INVALID_SHADER_NV);
return GetShaderCodeImpl(context, glCaps, patchedSources, shaderCodeOut); return GetShaderCodeImpl(context, glCaps, enableSeamfulCubeMapEmulation, patchedSources,
shaderCodeOut);
} }
else else
{ {
return GetShaderCodeImpl(context, glCaps, shaderSources, shaderCodeOut); return GetShaderCodeImpl(context, glCaps, enableSeamfulCubeMapEmulation, shaderSources,
shaderCodeOut);
} }
} }
// static // static
angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context, angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableSeamfulCubeMapEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{ {
...@@ -1000,6 +1005,11 @@ angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context, ...@@ -1000,6 +1005,11 @@ angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context,
glslang::TShader *shader = shaders[shaderType]; glslang::TShader *shader = shaders[shaderType];
shader->setStringsWithLengths(&shaderString, &shaderLength, 1); shader->setStringsWithLengths(&shaderString, &shaderLength, 1);
shader->setEntryPoint("main"); shader->setEntryPoint("main");
if (enableSeamfulCubeMapEmulation)
{
// Enable SPIR-V 1.3 if this workaround is used, as it uses subgroup operations.
shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
}
bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages); bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!result) if (!result)
......
...@@ -29,12 +29,14 @@ class GlslangWrapper ...@@ -29,12 +29,14 @@ class GlslangWrapper
static angle::Result GetShaderCode(vk::Context *context, static angle::Result GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation, bool enableLineRasterEmulation,
bool enableSeamfulCubeMapEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut); gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
private: private:
static angle::Result GetShaderCodeImpl(vk::Context *context, static angle::Result GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableSeamfulCubeMapEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut); gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
}; };
......
...@@ -306,7 +306,8 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk, ...@@ -306,7 +306,8 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
gl::ShaderMap<std::vector<uint32_t>> shaderCodes; gl::ShaderMap<std::vector<uint32_t>> shaderCodes;
ANGLE_TRY(GlslangWrapper::GetShaderCode( ANGLE_TRY(GlslangWrapper::GetShaderCode(
contextVk, contextVk->getCaps(), enableLineRasterEmulation, shaderSources, &shaderCodes)); contextVk, contextVk->getCaps(), enableLineRasterEmulation,
contextVk->emulateSeamfulCubeMapSampling(), shaderSources, &shaderCodes));
for (const gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
...@@ -1436,6 +1437,8 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk) ...@@ -1436,6 +1437,8 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk)
const gl::ActiveTextureArray<TextureVk *> &activeTextures = contextVk->getActiveTextures(); const gl::ActiveTextureArray<TextureVk *> &activeTextures = contextVk->getActiveTextures();
bool emulateSeamfulCubeMapSampling = contextVk->emulateSeamfulCubeMapSampling();
for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size(); for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
++textureIndex) ++textureIndex)
{ {
...@@ -1457,6 +1460,13 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk) ...@@ -1457,6 +1460,13 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk)
imageInfo.imageView = textureVk->getReadImageView().getHandle(); imageInfo.imageView = textureVk->getReadImageView().getHandle();
imageInfo.imageLayout = image.getCurrentLayout(); imageInfo.imageLayout = image.getCurrentLayout();
if (emulateSeamfulCubeMapSampling)
{
// If emulating seamful cubemapping, use the fetch image view. This is basically
// the same image view as read, except it's a 2DArray view for cube maps.
imageInfo.imageView = textureVk->getFetchImageView().getHandle();
}
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[writeCount]; VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[writeCount];
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
......
...@@ -490,6 +490,7 @@ RendererVk::RendererVk() ...@@ -490,6 +490,7 @@ RendererVk::RendererVk()
mDebugUtilsMessenger(VK_NULL_HANDLE), mDebugUtilsMessenger(VK_NULL_HANDLE),
mDebugReportCallback(VK_NULL_HANDLE), mDebugReportCallback(VK_NULL_HANDLE),
mPhysicalDevice(VK_NULL_HANDLE), mPhysicalDevice(VK_NULL_HANDLE),
mPhysicalDeviceSubgroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES},
mQueue(VK_NULL_HANDLE), mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mMaxVertexAttribDivisor(1), mMaxVertexAttribDivisor(1),
...@@ -1005,6 +1006,15 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1005,6 +1006,15 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
createInfo.pEnabledFeatures = &enabledFeatures.features; createInfo.pEnabledFeatures = &enabledFeatures.features;
} }
if (vkGetPhysicalDeviceProperties2KHR)
{
VkPhysicalDeviceProperties2 deviceProperties = {};
deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
deviceProperties.pNext = &mPhysicalDeviceSubgroupProperties;
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
}
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
createInfo.ppEnabledExtensionNames = createInfo.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data(); enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
...@@ -1264,6 +1274,11 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames) ...@@ -1264,6 +1274,11 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
mFeatures.perFrameWindowSizeQuery.enabled = true; mFeatures.perFrameWindowSizeQuery.enabled = true;
} }
if (IsWindows() && IsAMD(mPhysicalDeviceProperties.vendorID))
{
mFeatures.disallowSeamfulCubeMapEmulation.enabled = true;
}
if (IsAndroid() && IsQualcomm(mPhysicalDeviceProperties.vendorID)) if (IsAndroid() && IsQualcomm(mPhysicalDeviceProperties.vendorID))
{ {
mFeatures.forceD16TexFilter.enabled = true; mFeatures.forceD16TexFilter.enabled = true;
......
...@@ -72,6 +72,10 @@ class RendererVk : angle::NonCopyable ...@@ -72,6 +72,10 @@ class RendererVk : angle::NonCopyable
{ {
return mPhysicalDeviceProperties; return mPhysicalDeviceProperties;
} }
const VkPhysicalDeviceSubgroupProperties &getPhysicalDeviceSubgroupProperties() const
{
return mPhysicalDeviceSubgroupProperties;
}
const VkPhysicalDeviceFeatures &getPhysicalDeviceFeatures() const const VkPhysicalDeviceFeatures &getPhysicalDeviceFeatures() const
{ {
return mPhysicalDeviceFeatures; return mPhysicalDeviceFeatures;
...@@ -190,6 +194,7 @@ class RendererVk : angle::NonCopyable ...@@ -190,6 +194,7 @@ class RendererVk : angle::NonCopyable
VkDebugReportCallbackEXT mDebugReportCallback; VkDebugReportCallbackEXT mDebugReportCallback;
VkPhysicalDevice mPhysicalDevice; VkPhysicalDevice mPhysicalDevice;
VkPhysicalDeviceProperties mPhysicalDeviceProperties; VkPhysicalDeviceProperties mPhysicalDeviceProperties;
VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties;
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures; VkPhysicalDeviceFeatures mPhysicalDeviceFeatures;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties; std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
std::mutex mQueueMutex; std::mutex mQueueMutex;
......
...@@ -40,6 +40,11 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte ...@@ -40,6 +40,11 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte
compileOptions |= SH_CLAMP_POINT_SIZE; compileOptions |= SH_CLAMP_POINT_SIZE;
} }
if (contextVk->emulateSeamfulCubeMapSampling())
{
compileOptions |= SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING;
}
return compileImpl(context, compilerInstance, mData.getSource(), compileOptions | options); return compileImpl(context, compilerInstance, mData.getSource(), compileOptions | options);
} }
......
...@@ -153,7 +153,8 @@ class TextureVk : public TextureImpl ...@@ -153,7 +153,8 @@ class TextureVk : public TextureImpl
void releaseOwnershipOfImage(const gl::Context *context); void releaseOwnershipOfImage(const gl::Context *context);
const vk::ImageView &getReadImageView() const; const vk::ImageView &getReadImageView() const;
// A special view for cube maps as a 2D array, used with shaders that do texelFetch(). // A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for
// seamful cube map emulation.
const vk::ImageView &getFetchImageView() const; const vk::ImageView &getFetchImageView() const;
angle::Result getLayerLevelDrawImageView(vk::Context *context, angle::Result getLayerLevelDrawImageView(vk::Context *context,
size_t layer, size_t layer,
......
...@@ -280,9 +280,6 @@ ...@@ -280,9 +280,6 @@
3309 NEXUS5X GLES : dEQP-GLES2.functional.uniform_api.random.3 = FAIL 3309 NEXUS5X GLES : dEQP-GLES2.functional.uniform_api.random.3 = FAIL
3309 NEXUS5X GLES : dEQP-GLES2.functional.uniform_api.random.54 = FAIL 3309 NEXUS5X GLES : dEQP-GLES2.functional.uniform_api.random.54 = FAIL
// General Vulkan failures
3300 VULKAN : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL
// Only seen failing on Android // Only seen failing on Android
3241 VULKAN ANDROID : dEQP-GLES2.functional.depth_stencil_clear.depth_scissored_masked = FAIL 3241 VULKAN ANDROID : dEQP-GLES2.functional.depth_stencil_clear.depth_scissored_masked = FAIL
...@@ -290,13 +287,6 @@ ...@@ -290,13 +287,6 @@
3253 VULKAN : dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center = FAIL 3253 VULKAN : dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center = FAIL
3253 VULKAN : dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner = FAIL 3253 VULKAN : dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner = FAIL
// These seem to fail on both D3D11 and Vulkan
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_nearest = FAIL
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_linear = FAIL
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_nearest = FAIL
3243 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL
// D3D11 AMD already covered by Line 148 // D3D11 AMD already covered by Line 148
3243 D3D11 INTEL : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL 3243 D3D11 INTEL : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
3243 D3D11 INTEL : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL 3243 D3D11 INTEL : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
...@@ -312,16 +302,6 @@ ...@@ -312,16 +302,6 @@
3243 D3D11 NVIDIA : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL 3243 D3D11 NVIDIA : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL
// Fail with very tiny pixel differences // Fail with very tiny pixel differences
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_mirror = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_clamp = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_repeat = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_mirror = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_clamp = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_repeat = FAIL
3240 VULKAN : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_mirror = FAIL
3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp = FAIL 3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp = FAIL
3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror = FAIL 3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror = FAIL
3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp = FAIL 3240 D3D11 : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp = FAIL
...@@ -349,6 +329,44 @@ ...@@ -349,6 +329,44 @@
3306 VULKAN ANDROID : dEQP-GLES2.functional.polygon_offset.fixed16_factor_1_slope = FAIL 3306 VULKAN ANDROID : dEQP-GLES2.functional.polygon_offset.fixed16_factor_1_slope = FAIL
3307 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.projected.nearest_linear = FAIL 3307 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.projected.nearest_linear = FAIL
// Seamful cubemap sampling failures on Android (due to missing support subgroupQuad* operations).
3243 VULKAN ANDROID : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_nearest = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_linear = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_nearest = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_mirror = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_clamp = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_repeat = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_mirror = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_clamp = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_repeat = FAIL
3243 VULKAN ANDROID : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_mirror = FAIL
// These tests also fail on AMD windows driver as it is not allowed to use emulation due to errors.
3243 VULKAN WIN AMD : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_nearest = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_linear = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_nearest = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_mirror = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_clamp = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_repeat = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_mirror = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_clamp = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_repeat = FAIL
3243 VULKAN WIN AMD : dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_mirror = FAIL
// Vulkan AMD drivers don't seem to support wide point clipping. // Vulkan AMD drivers don't seem to support wide point clipping.
2463 VULKAN WIN AMD : dEQP-GLES2.functional.clipping.point.wide_point_clip = FAIL 2463 VULKAN WIN AMD : dEQP-GLES2.functional.clipping.point.wide_point_clip = FAIL
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// //
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle; using namespace angle;
...@@ -112,6 +113,154 @@ TEST_P(CubeMapTextureTest, RenderToFacesConsecutively) ...@@ -112,6 +113,154 @@ TEST_P(CubeMapTextureTest, RenderToFacesConsecutively)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Verify that cube map sampling follows the rules that map cubemap coordinates to coordinates
// within each face. See section 3.7.5 of GLES2.0 (Cube Map Texture Selection).
TEST_P(CubeMapTextureTest, SampleCoordinateTransform)
{
// Fails to compile the shader. anglebug.com/3776
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
constexpr GLsizei kCubeFaceCount = 6;
constexpr GLsizei kCubeFaceSectionCount = 4;
constexpr GLsizei kCubeFaceSectionCountSqrt = 2;
constexpr GLColor faceColors[kCubeFaceCount][kCubeFaceSectionCount] = {
{GLColor(255, 0, 0, 255), GLColor(191, 0, 0, 255), GLColor(127, 0, 0, 255),
GLColor(63, 0, 0, 255)},
{GLColor(0, 255, 0, 255), GLColor(0, 191, 0, 255), GLColor(0, 127, 0, 255),
GLColor(0, 63, 0, 255)},
{GLColor(0, 0, 255, 255), GLColor(0, 0, 191, 255), GLColor(0, 0, 127, 255),
GLColor(0, 0, 63, 255)},
{GLColor(255, 63, 0, 255), GLColor(191, 127, 0, 255), GLColor(127, 191, 0, 255),
GLColor(63, 255, 0, 255)},
{GLColor(0, 255, 63, 255), GLColor(0, 191, 127, 255), GLColor(0, 127, 191, 255),
GLColor(0, 63, 255, 255)},
{GLColor(63, 0, 255, 255), GLColor(127, 0, 191, 255), GLColor(191, 0, 127, 255),
GLColor(255, 0, 63, 255)},
};
constexpr GLsizei kTextureSize = 32;
GLTexture tex;
glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
for (GLenum face = 0; face < kCubeFaceCount; face++)
{
std::vector<GLColor> faceData(kTextureSize * kTextureSize);
// Create the face with four sections, each with a solid color from |faceColors|.
for (size_t row = 0; row < kTextureSize / kCubeFaceSectionCountSqrt; ++row)
{
for (size_t col = 0; col < kTextureSize / kCubeFaceSectionCountSqrt; ++col)
{
for (size_t srow = 0; srow < kCubeFaceSectionCountSqrt; ++srow)
{
for (size_t scol = 0; scol < kCubeFaceSectionCountSqrt; ++scol)
{
size_t r = row + srow * kTextureSize / kCubeFaceSectionCountSqrt;
size_t c = col + scol * kTextureSize / kCubeFaceSectionCountSqrt;
size_t s = srow * kCubeFaceSectionCountSqrt + scol;
faceData[r * kTextureSize + c] = faceColors[face][s];
}
}
}
}
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, kTextureSize, kTextureSize,
0, GL_RGBA, GL_UNSIGNED_BYTE, faceData.data());
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
EXPECT_GL_NO_ERROR();
GLTexture fboTex;
glBindTexture(GL_TEXTURE_2D, fboTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeFaceCount, kCubeFaceSectionCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
EXPECT_GL_NO_ERROR();
// Create a program that samples from 6x4 directions of the cubemap, draw and verify that the
// colors match the right color from |faceColors|.
constexpr char kFS[] = R"(precision mediump float;
uniform samplerCube texCube;
const mat4 coordInSection = mat4(
vec4(-0.5, -0.5, 0, 0),
vec4( 0.5, -0.5, 0, 0),
vec4(-0.5, 0.5, 0, 0),
vec4( 0.5, 0.5, 0, 0)
);
void main()
{
vec3 coord;
if (gl_FragCoord.x < 2.0)
{
coord.x = gl_FragCoord.x < 1.0 ? 1.0 : -1.0;
coord.zy = coordInSection[int(gl_FragCoord.y)].xy;
}
else if (gl_FragCoord.x < 4.0)
{
coord.y = gl_FragCoord.x < 3.0 ? 1.0 : -1.0;
coord.xz = coordInSection[int(gl_FragCoord.y)].xy;
}
else
{
coord.z = gl_FragCoord.x < 5.0 ? 1.0 : -1.0;
coord.xy = coordInSection[int(gl_FragCoord.y)].xy;
}
gl_FragColor = textureCube(texCube, coord);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
glUseProgram(program);
GLint texCubeLocation = glGetUniformLocation(program, "texCube");
ASSERT_NE(-1, texCubeLocation);
glUniform1i(texCubeLocation, 0);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
for (GLenum face = 0; face < kCubeFaceCount; face++)
{
// The following table defines the translation from textureCube coordinates to coordinates
// in each face. The framebuffer has width 6 and height 4. Every column corresponding to
// an x value represents one cube face. The values in rows are samples from the four
// sections of the face.
//
// Major Axis Direction Target sc tc ma
// +rx TEXTURE_CUBE_MAP_POSITIVE_X −rz −ry rx
// −rx TEXTURE_CUBE_MAP_NEGATIVE_X rz −ry rx
// +ry TEXTURE_CUBE_MAP_POSITIVE_Y rx rz ry
// −ry TEXTURE_CUBE_MAP_NEGATIVE_Y rx −rz ry
// +rz TEXTURE_CUBE_MAP_POSITIVE_Z rx −ry rz
// −rz TEXTURE_CUBE_MAP_NEGATIVE_Z −rx −ry rz
//
// This table is used only to determine the direction of growth for s and t. The shader
// always generates (row,col) coordinates (0, 0), (0, 1), (1, 0), (1, 1) which is the order
// the data is uploaded to the faces, but based on the table above, the sample order would
// be different.
constexpr size_t faceSampledSections[kCubeFaceCount][kCubeFaceSectionCount] = {
{3, 2, 1, 0}, {2, 3, 0, 1}, {0, 1, 2, 3}, {2, 3, 0, 1}, {2, 3, 0, 1}, {3, 2, 1, 0},
};
for (size_t section = 0; section < kCubeFaceSectionCount; ++section)
{
const GLColor sectionColor = faceColors[face][faceSampledSections[face][section]];
EXPECT_PIXEL_COLOR_EQ(face, section, sectionColor)
<< "face " << face << ", section " << section;
}
}
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(CubeMapTextureTest, ANGLE_INSTANTIATE_TEST(CubeMapTextureTest,
...@@ -120,4 +269,5 @@ ANGLE_INSTANTIATE_TEST(CubeMapTextureTest, ...@@ -120,4 +269,5 @@ ANGLE_INSTANTIATE_TEST(CubeMapTextureTest,
ES3_OPENGL(), ES3_OPENGL(),
ES2_OPENGLES(), ES2_OPENGLES(),
ES3_OPENGLES(), ES3_OPENGLES(),
ES2_VULKAN()); ES2_VULKAN(),
ES3_VULKAN());
...@@ -176,18 +176,10 @@ bool ShouldAlwaysForceNewDisplay() ...@@ -176,18 +176,10 @@ bool ShouldAlwaysForceNewDisplay()
} }
} // anonymous namespace } // anonymous namespace
GLColorRGB::GLColorRGB() : R(0), G(0), B(0) {}
GLColorRGB::GLColorRGB(GLubyte r, GLubyte g, GLubyte b) : R(r), G(g), B(b) {}
GLColorRGB::GLColorRGB(const Vector3 &floatColor) GLColorRGB::GLColorRGB(const Vector3 &floatColor)
: R(ColorDenorm(floatColor.x())), G(ColorDenorm(floatColor.y())), B(ColorDenorm(floatColor.z())) : R(ColorDenorm(floatColor.x())), G(ColorDenorm(floatColor.y())), B(ColorDenorm(floatColor.z()))
{} {}
GLColor::GLColor() : R(0), G(0), B(0), A(0) {}
GLColor::GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b), A(a) {}
GLColor::GLColor(const Vector4 &floatColor) GLColor::GLColor(const Vector4 &floatColor)
: R(ColorDenorm(floatColor.x())), : R(ColorDenorm(floatColor.x())),
G(ColorDenorm(floatColor.y())), G(ColorDenorm(floatColor.y())),
......
...@@ -76,8 +76,8 @@ namespace angle ...@@ -76,8 +76,8 @@ namespace angle
{ {
struct GLColorRGB struct GLColorRGB
{ {
GLColorRGB(); constexpr GLColorRGB() : R(0), G(0), B(0) {}
GLColorRGB(GLubyte r, GLubyte g, GLubyte b); constexpr GLColorRGB(GLubyte r, GLubyte g, GLubyte b) : R(r), G(g), B(b) {}
GLColorRGB(const angle::Vector3 &floatColor); GLColorRGB(const angle::Vector3 &floatColor);
const GLubyte *data() const { return &R; } const GLubyte *data() const { return &R; }
...@@ -94,8 +94,8 @@ struct GLColorRGB ...@@ -94,8 +94,8 @@ struct GLColorRGB
struct GLColor struct GLColor
{ {
GLColor(); constexpr GLColor() : R(0), G(0), B(0), A(0) {}
GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a); constexpr GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b), A(a) {}
GLColor(const angle::Vector4 &floatColor); GLColor(const angle::Vector4 &floatColor);
GLColor(GLuint colorValue); GLColor(GLuint colorValue);
......
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