Commit 2ffff6d0 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support image buffers

This change does not support reinterpreted formats yet. Additionally, despite lack of support for RGB32 formats, EXT_texture_buffer is exposed by this extension. Those formats don't support the STORAGE_TEXEL_BUFFER feature on any known hardware. Bug: angleproject:3573 Change-Id: I85f45eb23f6a0aa533488bb98d9f226d59af4d76 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2534395 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2eb85a5b
...@@ -185,6 +185,46 @@ TextureType SamplerTypeToTextureType(GLenum samplerType) ...@@ -185,6 +185,46 @@ TextureType SamplerTypeToTextureType(GLenum samplerType)
} }
} }
TextureType ImageTypeToTextureType(GLenum imageType)
{
switch (imageType)
{
case GL_IMAGE_2D:
case GL_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_2D:
return TextureType::_2D;
case GL_IMAGE_CUBE:
case GL_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_CUBE:
return TextureType::CubeMap;
case GL_IMAGE_CUBE_MAP_ARRAY:
case GL_INT_IMAGE_CUBE_MAP_ARRAY:
case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
return TextureType::CubeMapArray;
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
return TextureType::_2DArray;
case GL_IMAGE_3D:
case GL_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_3D:
return TextureType::_3D;
case GL_IMAGE_BUFFER:
case GL_INT_IMAGE_BUFFER:
case GL_UNSIGNED_INT_IMAGE_BUFFER:
return TextureType::Buffer;
default:
UNREACHABLE();
return TextureType::InvalidEnum;
}
}
bool IsMultisampled(TextureType type) bool IsMultisampled(TextureType type)
{ {
switch (type) switch (type)
......
...@@ -219,6 +219,7 @@ template <typename T> ...@@ -219,6 +219,7 @@ template <typename T>
using ShaderMap = angle::PackedEnumMap<ShaderType, T>; using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
TextureType SamplerTypeToTextureType(GLenum samplerType); TextureType SamplerTypeToTextureType(GLenum samplerType);
TextureType ImageTypeToTextureType(GLenum imageType);
bool IsMultisampled(gl::TextureType type); bool IsMultisampled(gl::TextureType type);
bool IsArrayTextureType(gl::TextureType type); bool IsArrayTextureType(gl::TextureType type);
......
...@@ -1063,8 +1063,11 @@ ProgramAliasedBindings::const_iterator ProgramAliasedBindings::end() const ...@@ -1063,8 +1063,11 @@ ProgramAliasedBindings::const_iterator ProgramAliasedBindings::end() const
} }
// ImageBinding implementation. // ImageBinding implementation.
ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0) {} ImageBinding::ImageBinding(size_t count, TextureType textureTypeIn)
ImageBinding::ImageBinding(GLuint imageUnit, size_t count) : textureType(textureTypeIn), boundImageUnits(count, 0)
{}
ImageBinding::ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn)
: textureType(textureTypeIn)
{ {
for (size_t index = 0; index < count; ++index) for (size_t index = 0; index < count; ++index)
{ {
...@@ -3723,15 +3726,18 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms) ...@@ -3723,15 +3726,18 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
// cannot load values into a uniform defined as an image. if declare without a // cannot load values into a uniform defined as an image. if declare without a
// binding qualifier, any uniform image variable (include all elements of // binding qualifier, any uniform image variable (include all elements of
// unbound image array) shoud be bound to unit zero. // unbound image array) shoud be bound to unit zero.
auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex]; auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex];
TextureType textureType = ImageTypeToTextureType(imageUniform.type);
if (imageUniform.binding == -1) if (imageUniform.binding == -1)
{ {
imageBindings.emplace_back(ImageBinding(imageUniform.getBasicTypeElementCount())); imageBindings.emplace_back(
ImageBinding(imageUniform.getBasicTypeElementCount(), textureType));
} }
else else
{ {
imageBindings.emplace_back(ImageBinding(imageUniform.binding + arrayOffset, imageBindings.emplace_back(ImageBinding(imageUniform.binding + arrayOffset,
imageUniform.getBasicTypeElementCount())); imageUniform.getBasicTypeElementCount(),
textureType));
} }
GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u; GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u;
...@@ -5308,6 +5314,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -5308,6 +5314,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
for (const auto &imageBinding : mState.getImageBindings()) for (const auto &imageBinding : mState.getImageBindings())
{ {
stream.writeInt(imageBinding.boundImageUnits.size()); stream.writeInt(imageBinding.boundImageUnits.size());
stream.writeInt(static_cast<unsigned int>(imageBinding.textureType));
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i) for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{ {
stream.writeInt(imageBinding.boundImageUnits[i]); stream.writeInt(imageBinding.boundImageUnits[i]);
...@@ -5558,8 +5565,9 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5558,8 +5565,9 @@ angle::Result Program::deserialize(const Context *context,
size_t imageBindingCount = stream.readInt<size_t>(); size_t imageBindingCount = stream.readInt<size_t>();
for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex) for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{ {
size_t elementCount = stream.readInt<size_t>(); size_t elementCount = stream.readInt<size_t>();
ImageBinding imageBinding(elementCount); TextureType textureType = static_cast<TextureType>(stream.readInt<unsigned int>());
ImageBinding imageBinding(elementCount, textureType);
for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex) for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
{ {
imageBinding.boundImageUnits[elementIndex] = stream.readInt<unsigned int>(); imageBinding.boundImageUnits[elementIndex] = stream.readInt<unsigned int>();
......
...@@ -45,11 +45,14 @@ struct SamplerBinding ...@@ -45,11 +45,14 @@ struct SamplerBinding
struct ImageBinding struct ImageBinding
{ {
ImageBinding(size_t count); ImageBinding(size_t count, TextureType textureTypeIn);
ImageBinding(GLuint imageUnit, size_t count); ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn);
ImageBinding(const ImageBinding &other); ImageBinding(const ImageBinding &other);
~ImageBinding(); ~ImageBinding();
// Necessary for distinguishing between textures with images and texture buffers.
TextureType textureType;
// List of all textures bound. // List of all textures bound.
// Cropped by the amount of unused elements reported by the driver. // Cropped by the amount of unused elements reported by the driver.
std::vector<GLuint> boundImageUnits; std::vector<GLuint> boundImageUnits;
......
...@@ -316,7 +316,8 @@ angle::Result BufferVk::setDataWithMemoryType(const gl::Context *context, ...@@ -316,7 +316,8 @@ angle::Result BufferVk::setDataWithMemoryType(const gl::Context *context,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled) if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{ {
......
...@@ -3906,40 +3906,71 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context, ...@@ -3906,40 +3906,71 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
continue; continue;
} }
TextureVk *textureVk = vk::GetImpl(texture); TextureVk *textureVk = vk::GetImpl(texture);
vk::ImageHelper *image = &textureVk->getImage();
mActiveImages[imageUnitIndex] = textureVk; mActiveImages[imageUnitIndex] = textureVk;
if (alreadyProcessed.find(image) != alreadyProcessed.end())
{
continue;
}
alreadyProcessed.insert(image);
// The image should be flushed and ready to use at this point. There may still be // The image should be flushed and ready to use at this point. There may still be
// lingering staged updates in its staging buffer for unused texture mip levels or // lingering staged updates in its staging buffer for unused texture mip levels or
// layers. Therefore we can't verify it has no staged updates right here. // layers. Therefore we can't verify it has no staged updates right here.
vk::ImageLayout imageLayout; gl::ShaderBitSet shaderStages = activeImageShaderBits[imageUnitIndex];
gl::ShaderBitSet shaderBits = activeImageShaderBits[imageUnitIndex];
if (shaderBits.any()) // TODO: PPOs don't initialize mActiveImageShaderBits. http://anglebug.com/5358
// Once that is fixed, the following if should be replaced with an assertion:
//
// ASSERT(shaderStages.any());
if (shaderStages.none())
{ {
gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderBits.bits())); if (executable->isCompute())
shaderBits.reset(shader);
// This is accessed by multiple shaders
if (shaderBits.any())
{ {
imageLayout = vk::ImageLayout::AllGraphicsShadersWrite; shaderStages.set(gl::ShaderType::Compute);
} }
else else
{ {
imageLayout = kShaderWriteImageLayouts[shader]; shaderStages.set();
shaderStages.reset(gl::ShaderType::Compute);
} }
} }
else
// Special handling of texture buffers. They have a buffer attached instead of an image.
if (texture->getType() == gl::TextureType::Buffer)
{
BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
vk::BufferHelper &buffer = bufferVk->getBuffer();
// TODO: accept multiple stages in bufferWrite. http://anglebug.com/3573
for (gl::ShaderType stage : shaderStages)
{
commandBufferHelper->bufferWrite(
&mResourceUseList, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
}
textureVk->retainBufferView(&mResourceUseList);
continue;
}
vk::ImageHelper *image = &textureVk->getImage();
if (alreadyProcessed.find(image) != alreadyProcessed.end())
{
continue;
}
alreadyProcessed.insert(image);
vk::ImageLayout imageLayout;
gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderStages.bits()));
shaderStages.reset(shader);
// This is accessed by multiple shaders
if (shaderStages.any())
{ {
imageLayout = vk::ImageLayout::AllGraphicsShadersWrite; imageLayout = vk::ImageLayout::AllGraphicsShadersWrite;
} }
else
{
imageLayout = kShaderWriteImageLayouts[shader];
}
VkImageAspectFlags aspectFlags = image->getAspectFlags(); VkImageAspectFlags aspectFlags = image->getAspectFlags();
uint32_t layerStart = 0; uint32_t layerStart = 0;
......
...@@ -508,8 +508,11 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable ...@@ -508,8 +508,11 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable
GetImageNameWithoutIndices(&imageName); GetImageNameWithoutIndices(&imageName);
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][imageName]; ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][imageName];
VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType]; VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType];
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, arraySize, activeStages,
nullptr); const VkDescriptorType descType = imageBinding.textureType == gl::TextureType::Buffer
? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
} }
} }
} }
...@@ -1205,7 +1208,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1205,7 +1208,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
std::string mappedImageName; std::string mappedImageName;
if (!useOldRewriteStructSamplers) if (!useOldRewriteStructSamplers)
{ {
mappedImageName = GlslangGetMappedSamplerName(imageUniform.mappedName); mappedImageName = GlslangGetMappedSamplerName(imageUniform.name);
} }
else else
{ {
...@@ -1225,8 +1228,34 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1225,8 +1228,34 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
mappedImageNameToArrayOffset[mappedImageName] += arraySize; mappedImageNameToArrayOffset[mappedImageName] += arraySize;
} }
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
// Texture buffers use buffer views, so they are especially handled.
if (imageBinding.textureType == gl::TextureType::Buffer)
{
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
TextureVk *textureVk = activeImages[imageUnit];
const vk::BufferView &view = textureVk->getBufferViewAndRecordUse(contextVk);
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][mappedImageName];
writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfos[arrayElement].pNext = nullptr;
writeInfos[arrayElement].dstSet = descriptorSet;
writeInfos[arrayElement].dstBinding = info.binding;
writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
writeInfos[arrayElement].descriptorCount = 1;
writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr();
}
continue;
}
VkDescriptorImageInfo *imageInfos = contextVk->allocDescriptorImageInfos(arraySize); VkDescriptorImageInfo *imageInfos = contextVk->allocDescriptorImageInfos(arraySize);
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement) for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{ {
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement]; GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
......
...@@ -33,7 +33,7 @@ namespace rx ...@@ -33,7 +33,7 @@ namespace rx
// pipeline stage. Additionally, transform feedback buffers are bound from binding 2 and up. // pipeline stage. Additionally, transform feedback buffers are bound from binding 2 and up.
// - Set 2 contains all textures (including texture buffers). // - Set 2 contains all textures (including texture buffers).
// - Set 3 contains all other shader resources, such as uniform and storage blocks, atomic counter // - Set 3 contains all other shader resources, such as uniform and storage blocks, atomic counter
// buffers and images. // buffers, images and image buffers.
// ANGLE driver uniforms set index (binding is always 0): // ANGLE driver uniforms set index (binding is always 0):
enum DescriptorSetIndex : uint32_t enum DescriptorSetIndex : uint32_t
......
...@@ -157,11 +157,57 @@ bool GetTextureSRGBOverrideSupport(const RendererVk *rendererVk, ...@@ -157,11 +157,57 @@ bool GetTextureSRGBOverrideSupport(const RendererVk *rendererVk,
bool HasTextureBufferSupport(const RendererVk *rendererVk) bool HasTextureBufferSupport(const RendererVk *rendererVk)
{ {
// Only three formats don't have mandatory UNIFORM_TEXEL_BUFFER support in Vulkan. // The following formats don't have mandatory UNIFORM_TEXEL_BUFFER support in Vulkan.
const std::array<GLenum, 3> &optionalFormats = { //
GL_RGB32F, // VK_FORMAT_R32G32B32_UINT
GL_RGB32I, // VK_FORMAT_R32G32B32_SINT
GL_RGB32UI, // VK_FORMAT_R32G32B32_SFLOAT
//
// Additionally, the following formats don't have mandatory STORAGE_TEXEL_BUFFER support:
//
// VK_FORMAT_R8_UINT
// VK_FORMAT_R8_SINT
// VK_FORMAT_R8_UNORM
// VK_FORMAT_R8G8_UINT
// VK_FORMAT_R8G8_SINT
// VK_FORMAT_R8G8_UNORM
// VK_FORMAT_R16_UINT
// VK_FORMAT_R16_SINT
// VK_FORMAT_R16_SFLOAT
// VK_FORMAT_R16G16_UINT
// VK_FORMAT_R16G16_SINT
// VK_FORMAT_R16G16_SFLOAT
// VK_FORMAT_R32G32B32_UINT
// VK_FORMAT_R32G32B32_SINT
// VK_FORMAT_R32G32B32_SFLOAT
//
// The formats that have mandatory support for both features (and don't need to be checked) are:
//
// VK_FORMAT_R8G8B8A8_UINT
// VK_FORMAT_R8G8B8A8_SINT
// VK_FORMAT_R8G8B8A8_UNORM
// VK_FORMAT_R16G16B16A16_UINT
// VK_FORMAT_R16G16B16A16_SINT
// VK_FORMAT_R16G16B16A16_SFLOAT
// VK_FORMAT_R32_UINT
// VK_FORMAT_R32_SINT
// VK_FORMAT_R32_SFLOAT
// VK_FORMAT_R32G32_UINT
// VK_FORMAT_R32G32_SINT
// VK_FORMAT_R32G32_SFLOAT
// VK_FORMAT_R32G32B32A32_UINT
// VK_FORMAT_R32G32B32A32_SINT
// VK_FORMAT_R32G32B32A32_SFLOAT
//
// TODO: RGB32 formats currently don't have STORAGE_TEXEL_BUFFER support on any known platform.
// Despite this limitation, we expose EXT_texture_buffer. http://anglebug.com/3573
const std::array<GLenum, 12> &optionalFormats = {
GL_R8, GL_R8I, GL_R8UI, GL_RG8, GL_RG8I, GL_RG8UI,
GL_R16F, GL_R16I, GL_R16UI, GL_RG16F, GL_RG16I, GL_RG16UI,
// GL_RGB32F,
// GL_RGB32I,
// GL_RGB32UI,
}; };
for (GLenum formatGL : optionalFormats) for (GLenum formatGL : optionalFormats)
...@@ -169,7 +215,8 @@ bool HasTextureBufferSupport(const RendererVk *rendererVk) ...@@ -169,7 +215,8 @@ bool HasTextureBufferSupport(const RendererVk *rendererVk)
const vk::Format &formatVk = rendererVk->getFormat(formatGL); const vk::Format &formatVk = rendererVk->getFormat(formatGL);
if (!rendererVk->hasBufferFormatFeatureBits(formatVk.vkBufferFormat, if (!rendererVk->hasBufferFormatFeatureBits(formatVk.vkBufferFormat,
VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT |
VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
{ {
return false; return false;
} }
...@@ -773,8 +820,9 @@ void RendererVk::ensureCapsInitialized() const ...@@ -773,8 +820,9 @@ void RendererVk::ensureCapsInitialized() const
// Enable GL_EXT_texture_buffer and OES variant. Nearly all formats required for this extension // Enable GL_EXT_texture_buffer and OES variant. Nearly all formats required for this extension
// are also required to have the UNIFORM_TEXEL_BUFFER feature bit in Vulkan, except for // are also required to have the UNIFORM_TEXEL_BUFFER feature bit in Vulkan, except for
// R32G32B32_SFLOAT/UINT/SINT which are optional. This extension is exposed only if those // R32G32B32_SFLOAT/UINT/SINT which are optional. For many formats, the STORAGE_TEXEL_BUFFER
// formats support the necessary feature bit. // feature is optional though. This extension is exposed only if the formats specified in
// EXT_texture_buffer support the necessary feature bits.
if (vk::HasTextureBufferSupport(this)) if (vk::HasTextureBufferSupport(this))
{ {
mNativeExtensions.textureBufferOES = true; mNativeExtensions.textureBufferOES = true;
......
...@@ -186,8 +186,8 @@ ...@@ -186,8 +186,8 @@
// Cannot create 2D (array) view of 3D texture. // Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL 3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// Storage texel buffer support (part of EXT_texture_buffer) // Format reinterpretation support for storage texel buffers missing
3573 VULKAN : dEQP-GLES31.functional.image_load_store.buffer.* = SKIP 3573 VULKAN : dEQP-GLES31.functional.image_load_store.buffer.format_reinterpret.* = FAIL
//// ////
//// Android (i.e. Pixel*) Vulkan expectations //// Android (i.e. Pixel*) Vulkan expectations
......
...@@ -32,13 +32,7 @@ ...@@ -32,13 +32,7 @@
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set. // GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : KHR-GLES31.core.texture_gather.* = FAIL 3605 VULKAN : KHR-GLES31.core.texture_gather.* = FAIL
// Storage texel buffer support (part of EXT_texture_buffer) // No known implementation supports STORAGE_TEXEL_BUFFER support for RGB32 formats
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_buffer_load = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_cpu_writes = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_framebuffer_readback = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_transform_feedback = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_image_store = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_ssbo_writes = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP 3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP
// Dispatch indirect: // Dispatch indirect:
......
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