Commit 7a06ac1b by Luc Ferron Committed by Commit Bot

Vulkan: Dynamic update of uniforms

- This change enables us to update uniforms indefintely using VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor types. - Enables 219 new dEQP tests in the uniform_api namespace. - Creates a new white box test to validate new buffer allocation. Bug: angleproject:2392 Change-Id: I8146e6104a6b7727f63265a4671577d251a8fca8 Reviewed-on: https://chromium-review.googlesource.com/965929 Commit-Queue: Luc Ferron <lucferron@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent ba939718
...@@ -69,11 +69,13 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer) ...@@ -69,11 +69,13 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mDynamicDescriptorPool(), mDynamicDescriptorPool(),
mVertexArrayDirty(false), mVertexArrayDirty(false),
mTexturesDirty(false), mTexturesDirty(false),
mStreamingVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kStreamingVertexDataSize, 1), mStreamingVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kStreamingVertexDataSize),
mStreamingIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kStreamingIndexDataSize, 1) mStreamingIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kStreamingIndexDataSize)
{ {
memset(&mClearColorValue, 0, sizeof(mClearColorValue)); memset(&mClearColorValue, 0, sizeof(mClearColorValue));
memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue)); memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
mStreamingVertexData.init(1);
mStreamingIndexData.init(1);
} }
ContextVk::~ContextVk() ContextVk::~ContextVk()
...@@ -244,9 +246,12 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -244,9 +246,12 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
{ {
ASSERT(!descriptorSets.empty()); ASSERT(!descriptorSets.empty());
const vk::PipelineLayout &pipelineLayout = mRenderer->getGraphicsPipelineLayout(); const vk::PipelineLayout &pipelineLayout = mRenderer->getGraphicsPipelineLayout();
(*commandBuffer) (*commandBuffer)
->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, usedRange.low(), ->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, usedRange.low(),
usedRange.length(), &descriptorSets[usedRange.low()], 0, nullptr); usedRange.length(), &descriptorSets[usedRange.low()],
programVk->getDynamicOffsetsCount(),
programVk->getDynamicOffsets());
} }
return gl::NoError(); return gl::NoError();
...@@ -318,7 +323,7 @@ gl::Error ContextVk::drawElements(const gl::Context *context, ...@@ -318,7 +323,7 @@ gl::Error ContextVk::drawElements(const gl::Context *context,
const bool computeIndexRange = vk::GetImpl(vao)->attribsToStream(contextVk).any(); const bool computeIndexRange = vk::GetImpl(vao)->attribsToStream(contextVk).any();
gl::IndexRange range; gl::IndexRange range;
VkBuffer buffer = VK_NULL_HANDLE; VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceSize offset = 0; uint32_t offset = 0;
if (elementArrayBuffer) if (elementArrayBuffer)
{ {
......
...@@ -85,7 +85,7 @@ vk::Error DynamicDescriptorPool::allocateDescriptorSets( ...@@ -85,7 +85,7 @@ vk::Error DynamicDescriptorPool::allocateDescriptorSets(
vk::Error DynamicDescriptorPool::allocateNewPool(const VkDevice &device) vk::Error DynamicDescriptorPool::allocateNewPool(const VkDevice &device)
{ {
VkDescriptorPoolSize poolSizes[DescriptorPoolIndexCount]; VkDescriptorPoolSize poolSizes[DescriptorPoolIndexCount];
poolSizes[UniformBufferIndex].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[UniformBufferIndex].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
poolSizes[UniformBufferIndex].descriptorCount = poolSizes[UniformBufferIndex].descriptorCount =
mUniformBufferDescriptorsPerSet * kMaxSets / DescriptorPoolIndexCount; mUniformBufferDescriptorsPerSet * kMaxSets / DescriptorPoolIndexCount;
poolSizes[TextureIndex].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSizes[TextureIndex].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
......
...@@ -10,14 +10,19 @@ ...@@ -10,14 +10,19 @@
#ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_ #ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_
#define LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_ #define LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_
#include <array>
#include "libANGLE/Constants.h" #include "libANGLE/Constants.h"
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/StreamingBuffer.h"
#include "libANGLE/renderer/vulkan/vk_utils.h" #include "libANGLE/renderer/vulkan/vk_utils.h"
#include <array>
namespace rx namespace rx
{ {
namespace
{
constexpr uint32_t kShaderTypeCount = 2;
} // anonymous namespace.
class ProgramVk : public ProgramImpl class ProgramVk : public ProgramImpl
{ {
...@@ -107,6 +112,8 @@ class ProgramVk : public ProgramImpl ...@@ -107,6 +112,8 @@ class ProgramVk : public ProgramImpl
vk::Error updateUniforms(ContextVk *contextVk); vk::Error updateUniforms(ContextVk *contextVk);
const std::vector<VkDescriptorSet> &getDescriptorSets() const; const std::vector<VkDescriptorSet> &getDescriptorSets() const;
const uint32_t *getDynamicOffsets();
uint32_t getDynamicOffsetsCount();
// In Vulkan, it is invalid to pass in a NULL descriptor set to vkCmdBindDescriptorSets. // In Vulkan, it is invalid to pass in a NULL descriptor set to vkCmdBindDescriptorSets.
// However, it's valid to leave them in an undefined, unbound state, if they are never used. // However, it's valid to leave them in an undefined, unbound state, if they are never used.
...@@ -119,9 +126,12 @@ class ProgramVk : public ProgramImpl ...@@ -119,9 +126,12 @@ class ProgramVk : public ProgramImpl
void updateTexturesDescriptorSet(ContextVk *contextVk); void updateTexturesDescriptorSet(ContextVk *contextVk);
void invalidateTextures(); void invalidateTextures();
// For testing only.
void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
private: private:
vk::Error reset(ContextVk *contextVk); vk::Error reset(ContextVk *contextVk);
vk::Error initDescriptorSets(ContextVk *contextVk); vk::Error allocateDescriptorSets(ContextVk *contextVk);
gl::Error initDefaultUniformBlocks(const gl::Context *glContext); gl::Error initDefaultUniformBlocks(const gl::Context *glContext);
vk::Error updateDefaultUniformsDescriptorSet(ContextVk *contextVk); vk::Error updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
...@@ -142,7 +152,7 @@ class ProgramVk : public ProgramImpl ...@@ -142,7 +152,7 @@ class ProgramVk : public ProgramImpl
DefaultUniformBlock(); DefaultUniformBlock();
~DefaultUniformBlock(); ~DefaultUniformBlock();
vk::BufferAndMemory storage; StreamingBuffer storage;
// Shadow copies of the shader uniform data. // Shadow copies of the shader uniform data.
angle::MemoryBuffer uniformData; angle::MemoryBuffer uniformData;
...@@ -153,7 +163,8 @@ class ProgramVk : public ProgramImpl ...@@ -153,7 +163,8 @@ class ProgramVk : public ProgramImpl
std::vector<sh::BlockMemberInfo> uniformLayout; std::vector<sh::BlockMemberInfo> uniformLayout;
}; };
std::array<DefaultUniformBlock, 2> mDefaultUniformBlocks; std::array<DefaultUniformBlock, kShaderTypeCount> mDefaultUniformBlocks;
std::array<uint32_t, kShaderTypeCount> mUniformBlocksOffsets;
// This is a special "empty" placeholder buffer for when a shader has no uniforms. // This is a special "empty" placeholder buffer for when a shader has no uniforms.
// It is necessary because we want to keep a compatible pipeline layout in all cases, // It is necessary because we want to keep a compatible pipeline layout in all cases,
......
...@@ -829,7 +829,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout() ...@@ -829,7 +829,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
auto &layoutBinding = uniformBindings[blockCount]; auto &layoutBinding = uniformBindings[blockCount];
layoutBinding.binding = blockCount; layoutBinding.binding = blockCount;
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
layoutBinding.descriptorCount = 1; layoutBinding.descriptorCount = 1;
layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
layoutBinding.pImmutableSamplers = nullptr; layoutBinding.pImmutableSamplers = nullptr;
...@@ -841,7 +841,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout() ...@@ -841,7 +841,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
auto &layoutBinding = uniformBindings[blockCount]; auto &layoutBinding = uniformBindings[blockCount];
layoutBinding.binding = blockCount; layoutBinding.binding = blockCount;
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
layoutBinding.descriptorCount = 1; layoutBinding.descriptorCount = 1;
layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
layoutBinding.pImmutableSamplers = nullptr; layoutBinding.pImmutableSamplers = nullptr;
......
...@@ -17,35 +17,48 @@ ...@@ -17,35 +17,48 @@
namespace rx namespace rx
{ {
StreamingBuffer::StreamingBuffer(VkBufferUsageFlags usage, size_t minSize, size_t minAlignment) StreamingBuffer::StreamingBuffer(VkBufferUsageFlags usage, size_t minSize)
: mUsage(usage), : mUsage(usage),
mMinSize(minSize), mMinSize(minSize),
mNextWriteOffset(0), mNextWriteOffset(0),
mLastFlushOffset(0), mLastFlushOffset(0),
mSize(0), mSize(0),
mMinAlignment(minAlignment), mAlignment(0),
mMappedMemory(nullptr) mMappedMemory(nullptr)
{ {
} }
void StreamingBuffer::init(size_t alignment)
{
ASSERT(alignment > 0);
mAlignment = alignment;
}
StreamingBuffer::~StreamingBuffer() StreamingBuffer::~StreamingBuffer()
{ {
ASSERT(mAlignment == 0);
}
bool StreamingBuffer::valid()
{
return mAlignment > 0;
} }
gl::Error StreamingBuffer::allocate(ContextVk *context, vk::Error StreamingBuffer::allocate(ContextVk *context,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, VkBuffer *handleOut,
VkDeviceSize *offsetOut, uint32_t *offsetOut,
bool *outNewBufferAllocated) bool *outNewBufferAllocated)
{ {
ASSERT(valid());
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = context->getRenderer();
// TODO(fjhenigman): Update this when we have buffers that need to // TODO(fjhenigman): Update this when we have buffers that need to
// persist longer than one frame. // persist longer than one frame.
updateQueueSerial(renderer->getCurrentQueueSerial()); updateQueueSerial(renderer->getCurrentQueueSerial());
size_t sizeToAllocate = roundUp(sizeInBytes, mMinAlignment); size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextWriteOffset; angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextWriteOffset;
checkedNextWriteOffset += sizeToAllocate; checkedNextWriteOffset += sizeToAllocate;
...@@ -93,17 +106,21 @@ gl::Error StreamingBuffer::allocate(ContextVk *context, ...@@ -93,17 +106,21 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
} }
ASSERT(mBuffer.valid()); ASSERT(mBuffer.valid());
*handleOut = mBuffer.getHandle();
if (handleOut != nullptr)
{
*handleOut = mBuffer.getHandle();
}
ASSERT(mMappedMemory); ASSERT(mMappedMemory);
*ptrOut = mMappedMemory + mNextWriteOffset; *ptrOut = mMappedMemory + mNextWriteOffset;
*offsetOut = mNextWriteOffset; *offsetOut = mNextWriteOffset;
mNextWriteOffset += sizeToAllocate; mNextWriteOffset += static_cast<uint32_t>(sizeToAllocate);
return gl::NoError(); return vk::NoError();
} }
gl::Error StreamingBuffer::flush(ContextVk *context) vk::Error StreamingBuffer::flush(ContextVk *context)
{ {
if (mNextWriteOffset > mLastFlushOffset) if (mNextWriteOffset > mLastFlushOffset)
{ {
...@@ -117,13 +134,27 @@ gl::Error StreamingBuffer::flush(ContextVk *context) ...@@ -117,13 +134,27 @@ gl::Error StreamingBuffer::flush(ContextVk *context)
mLastFlushOffset = mNextWriteOffset; mLastFlushOffset = mNextWriteOffset;
} }
return gl::NoError(); return vk::NoError();
} }
void StreamingBuffer::destroy(VkDevice device) void StreamingBuffer::destroy(VkDevice device)
{ {
mAlignment = 0;
mBuffer.destroy(device); mBuffer.destroy(device);
mMemory.destroy(device); mMemory.destroy(device);
} }
VkBuffer StreamingBuffer::getCurrentBufferHandle() const
{
return mBuffer.getHandle();
}
void StreamingBuffer::setMinimumSize(size_t minSize)
{
// This will really only have an effect next time we call allocate.
mMinSize = minSize;
// Forces a new allocation on the next allocate.
mSize = 0;
}
} // namespace rx } // namespace rx
...@@ -19,26 +19,32 @@ namespace rx ...@@ -19,26 +19,32 @@ namespace rx
class StreamingBuffer : public ResourceVk class StreamingBuffer : public ResourceVk
{ {
public: public:
StreamingBuffer(VkBufferUsageFlags usage, size_t minSize, size_t minAlignment); StreamingBuffer(VkBufferUsageFlags usage, size_t minSize);
void init(size_t alignment);
bool valid();
~StreamingBuffer(); ~StreamingBuffer();
gl::Error allocate(ContextVk *context, vk::Error allocate(ContextVk *context,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, VkBuffer *handleOut,
VkDeviceSize *offsetOut, uint32_t *offsetOut,
bool *outNewBufferAllocated); bool *outNewBufferAllocated);
gl::Error flush(ContextVk *context); vk::Error flush(ContextVk *context);
void destroy(VkDevice device); void destroy(VkDevice device);
VkBuffer getCurrentBufferHandle() const;
// For testing only!
void setMinimumSize(size_t minSize);
private: private:
VkBufferUsageFlags mUsage; VkBufferUsageFlags mUsage;
size_t mMinSize; size_t mMinSize;
vk::Buffer mBuffer; vk::Buffer mBuffer;
vk::DeviceMemory mMemory; vk::DeviceMemory mMemory;
size_t mNextWriteOffset; uint32_t mNextWriteOffset;
size_t mLastFlushOffset; uint32_t mLastFlushOffset;
size_t mSize; size_t mSize;
size_t mMinAlignment; size_t mAlignment;
uint8_t *mMappedMemory; uint8_t *mMappedMemory;
}; };
......
...@@ -81,9 +81,10 @@ gl::Error VertexArrayVk::streamVertexData(ContextVk *context, ...@@ -81,9 +81,10 @@ gl::Error VertexArrayVk::streamVertexData(ContextVk *context,
const size_t lastByte = const size_t lastByte =
lastVertex * binding.getStride() + gl::ComputeVertexAttributeTypeSize(attrib); lastVertex * binding.getStride() + gl::ComputeVertexAttributeTypeSize(attrib);
uint8_t *dst = nullptr; uint8_t *dst = nullptr;
uint32_t offset = 0;
ANGLE_TRY(stream->allocate(context, lastByte, &dst, ANGLE_TRY(stream->allocate(context, lastByte, &dst,
&mCurrentArrayBufferHandles[attribIndex], &mCurrentArrayBufferHandles[attribIndex], &offset, nullptr));
&mCurrentArrayBufferOffsets[attribIndex], nullptr)); mCurrentArrayBufferOffsets[attribIndex] = static_cast<VkDeviceSize>(offset);
memcpy(dst + firstByte, static_cast<const uint8_t *>(attrib.pointer) + firstByte, memcpy(dst + firstByte, static_cast<const uint8_t *>(attrib.pointer) + firstByte,
lastByte - firstByte); lastByte - firstByte);
} }
......
...@@ -1367,11 +1367,11 @@ LineLoopHandler::LineLoopHandler() ...@@ -1367,11 +1367,11 @@ LineLoopHandler::LineLoopHandler()
: mObserverBinding(this, 0u), : mObserverBinding(this, 0u),
mStreamingLineLoopIndicesData( mStreamingLineLoopIndicesData(
new StreamingBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, new StreamingBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
kLineLoopStreamingBufferMinSize, kLineLoopStreamingBufferMinSize)),
1)),
mLineLoopIndexBuffer(VK_NULL_HANDLE), mLineLoopIndexBuffer(VK_NULL_HANDLE),
mLineLoopIndexBufferOffset(VK_NULL_HANDLE) mLineLoopIndexBufferOffset(VK_NULL_HANDLE)
{ {
mStreamingLineLoopIndicesData->init(1);
} }
LineLoopHandler::~LineLoopHandler() = default; LineLoopHandler::~LineLoopHandler() = default;
......
...@@ -724,7 +724,7 @@ class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface ...@@ -724,7 +724,7 @@ class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface
angle::ObserverBinding mObserverBinding; angle::ObserverBinding mObserverBinding;
std::unique_ptr<StreamingBuffer> mStreamingLineLoopIndicesData; std::unique_ptr<StreamingBuffer> mStreamingLineLoopIndicesData;
VkBuffer mLineLoopIndexBuffer; VkBuffer mLineLoopIndexBuffer;
VkDeviceSize mLineLoopIndexBufferOffset; uint32_t mLineLoopIndexBufferOffset;
Optional<int> mLineLoopBufferFirstIndex; Optional<int> mLineLoopBufferFirstIndex;
Optional<int> mLineLoopBufferLastIndex; Optional<int> mLineLoopBufferLastIndex;
}; };
......
...@@ -222,6 +222,7 @@ if (is_win || is_linux || is_mac || is_android) { ...@@ -222,6 +222,7 @@ if (is_win || is_linux || is_mac || is_android) {
if (angle_enable_vulkan) { if (angle_enable_vulkan) {
sources += [ "gl_tests/VulkanFormatTablesTest.cpp" ] sources += [ "gl_tests/VulkanFormatTablesTest.cpp" ]
sources += [ "gl_tests/VulkanUniformUpdatesTest.cpp" ]
} }
configs += [ configs += [
......
...@@ -232,7 +232,97 @@ ...@@ -232,7 +232,97 @@
2161 VULKAN : dEQP-GLES2.functional.rasterization.limits.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.rasterization.limits.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.attribute_location.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.attribute_location.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.multisample.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.multisample.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.multiple_basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.multiple_nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.unused_uniforms.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic.bool_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic.bvec2_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic.bvec3_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic.bvec4_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic.sampler* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.multiple_basic.vertex = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.multiple_basic.fragment = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.multiple_basic.both = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.multiple_basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.multiple_nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.basic.samplerCube_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.multiple_basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.multiple_nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.initial.render.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.ivec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.ivec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.ivec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.bool_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.bvec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.bvec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.bvec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic.sampler* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_array_first_elem_without_brackets.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.multiple_basic.vertex = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.multiple_basic.fragment = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.multiple_basic.both = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.multiple_basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.multiple_nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.mat2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.mat3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.ivec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.ivec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.ivec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.samplerCube* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.multiple_basic.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.ivec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.ivec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.ivec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.bool_api_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.bvec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.bvec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.bvec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.sampler* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_array_first_elem_without_brackets.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.multiple_basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.multiple_nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic.ivec2_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic.ivec3_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic.ivec4_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic.samplerCube* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.struct_in_array.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.array_in_struct.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.nested_structs_arrays.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_full.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_partial.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.unused_uniforms.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.random.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.read_pixels.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.read_pixels.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.depth_range.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.depth_range.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.dither.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.dither.* = SKIP
......
...@@ -1392,6 +1392,56 @@ TEST_P(SimpleStateChangeTest, ScissorTest) ...@@ -1392,6 +1392,56 @@ TEST_P(SimpleStateChangeTest, ScissorTest)
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red); EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
} }
// This test validates we are able to change the valid of a uniform dynamically.
TEST_P(SimpleStateChangeTest, UniformUpdateTest)
{
constexpr char kPositionUniformVertexShader[] = R"(
precision mediump float;
attribute vec2 position;
uniform vec2 uniPosModifier;
void main()
{
gl_Position = vec4(position + uniPosModifier, 0, 1);
})";
constexpr char kColorUniformFragmentShader[] = R"(
precision mediump float;
uniform vec4 uniColor;
void main()
{
gl_FragColor = uniColor;
})";
ANGLE_GL_PROGRAM(program, kPositionUniformVertexShader, kColorUniformFragmentShader);
glUseProgram(program);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint posUniformLocation = glGetUniformLocation(program, "uniPosModifier");
ASSERT_NE(posUniformLocation, -1);
GLint colorUniformLocation = glGetUniformLocation(program, "uniColor");
ASSERT_NE(colorUniformLocation, -1);
// draw a red quad to the left side.
glUniform2f(posUniformLocation, -0.5, 0.0);
glUniform4f(colorUniformLocation, 1.0, 0.0, 0.0, 1.0);
drawQuad(program.get(), "position", 0.0f, 0.5f, true);
// draw a green quad to the right side.
glUniform2f(posUniformLocation, 0.5, 0.0);
glUniform4f(colorUniformLocation, 0.0, 1.0, 0.0, 1.0);
drawQuad(program.get(), "position", 0.0f, 0.5f, true);
ASSERT_GL_NO_ERROR();
// Test the center of the left quad. Should be red.
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 2, GLColor::red);
// Test the center of the right quad. Should be green.
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4 * 3, getWindowHeight() / 2, GLColor::green);
}
// Tests that changing the storage of a Renderbuffer currently in use by GL works as expected. // Tests that changing the storage of a Renderbuffer currently in use by GL works as expected.
TEST_P(SimpleStateChangeTest, RedefineRenderbufferInUse) TEST_P(SimpleStateChangeTest, RedefineRenderbufferInUse)
{ {
......
//
// Copyright 2018 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.
//
// VulkanUniformUpdatesTest:
// Tests to validate our Vulkan dynamic uniform updates are working as expected.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_instantiate.h"
// 'None' is defined as 'struct None {};' in
// third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.
// But 'None' is also defined as a numeric constant 0L in <X11/X.h>.
// So we need to include ANGLETest.h first to avoid this conflict.
#include "libANGLE/Context.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
class VulkanUniformUpdatesTest : public ANGLETest
{
};
// This test updates a uniform until a new buffer is allocated and then make sure the uniform
// updates still work.
TEST_P(VulkanUniformUpdatesTest, UpdateUniformUntilNewBufferIsAllocated)
{
ASSERT_TRUE(IsVulkan());
constexpr char kPositionUniformVertexShader[] = R"(
precision mediump float;
attribute vec2 position;
uniform vec2 uniPosModifier;
void main()
{
gl_Position = vec4(position + uniPosModifier, 0, 1);
})";
constexpr char kColorUniformFragmentShader[] = R"(
precision mediump float;
uniform vec4 uniColor;
void main()
{
gl_FragColor = uniColor;
})";
// Hack the angle!
const gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
auto *contextVk = rx::GetImplAs<rx::ContextVk>(context);
ANGLE_GL_PROGRAM(program, kPositionUniformVertexShader, kColorUniformFragmentShader);
glUseProgram(program);
const gl::State &state = contextVk->getGLState();
rx::ProgramVk *programVk = rx::vk::GetImpl(state.getProgram());
// Set a really small min size so that uniform updates often allocates a new buffer.
programVk->setDefaultUniformBlocksMinSizeForTesting(128);
GLint posUniformLocation = glGetUniformLocation(program, "uniPosModifier");
ASSERT_NE(posUniformLocation, -1);
GLint colorUniformLocation = glGetUniformLocation(program, "uniColor");
ASSERT_NE(colorUniformLocation, -1);
// Sets both uniforms 10 times, it should certainly trigger new buffers creations by the
// underlying StreamingBuffer.
for (int i = 0; i < 100; i++)
{
glUniform2f(posUniformLocation, -0.5, 0.0);
glUniform4f(colorUniformLocation, 1.0, 0.0, 0.0, 1.0);
drawQuad(program, "position", 0.5f, 1.0f);
swapBuffers();
ASSERT_GL_NO_ERROR();
}
}
ANGLE_INSTANTIATE_TEST(VulkanUniformUpdatesTest, ES2_VULKAN());
} // anonymous namespace
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