Merge changes I87bf1147,I1bfc5656 into nyc-dev
* changes:
Enable blending for floating point formats
Always disable blending for 32bit float formats
diff --git a/android/cts/master/com.drawelements.deqp.vk.xml b/android/cts/master/com.drawelements.deqp.vk.xml
index 6a6cef9..3b93b5d 100644
--- a/android/cts/master/com.drawelements.deqp.vk.xml
+++ b/android/cts/master/com.drawelements.deqp.vk.xml
@@ -258753,6 +258753,12 @@
<Test name="create">
<TestInstance/>
</Test>
+ <Test name="create_custom_allocator">
+ <TestInstance/>
+ </Test>
+ <Test name="create_simulate_oom">
+ <TestInstance/>
+ </Test>
<Test name="query_support">
<TestInstance/>
</Test>
@@ -258802,6 +258808,38 @@
<TestInstance/>
</Test>
</TestCase>
+ <TestCase name="simulate_oom">
+ <Test name="min_image_count">
+ <TestInstance/>
+ </Test>
+ <Test name="image_format">
+ <TestInstance/>
+ </Test>
+ <Test name="image_extent">
+ <TestInstance/>
+ </Test>
+ <Test name="image_array_layers">
+ <TestInstance/>
+ </Test>
+ <Test name="image_usage">
+ <TestInstance/>
+ </Test>
+ <Test name="image_sharing_mode">
+ <TestInstance/>
+ </Test>
+ <Test name="pre_transform">
+ <TestInstance/>
+ </Test>
+ <Test name="composite_alpha">
+ <TestInstance/>
+ </Test>
+ <Test name="present_mode">
+ <TestInstance/>
+ </Test>
+ <Test name="clipped">
+ <TestInstance/>
+ </Test>
+ </TestCase>
</TestSuite>
</TestSuite>
</TestSuite>
diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt
index 67729e3..fdb1556 100644
--- a/android/cts/master/vk-master.txt
+++ b/android/cts/master/vk-master.txt
@@ -80289,6 +80289,8 @@
dEQP-VK.image.image_size.buffer.readonly_writeonly_1
dEQP-VK.image.image_size.buffer.readonly_writeonly_7
dEQP-VK.wsi.android.surface.create
+dEQP-VK.wsi.android.surface.create_custom_allocator
+dEQP-VK.wsi.android.surface.create_simulate_oom
dEQP-VK.wsi.android.surface.query_support
dEQP-VK.wsi.android.surface.query_capabilities
dEQP-VK.wsi.android.surface.query_formats
@@ -80304,6 +80306,16 @@
dEQP-VK.wsi.android.swapchain.create.composite_alpha
dEQP-VK.wsi.android.swapchain.create.present_mode
dEQP-VK.wsi.android.swapchain.create.clipped
+dEQP-VK.wsi.android.swapchain.simulate_oom.min_image_count
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_format
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_extent
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_array_layers
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_usage
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_sharing_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.pre_transform
+dEQP-VK.wsi.android.swapchain.simulate_oom.composite_alpha
+dEQP-VK.wsi.android.swapchain.simulate_oom.present_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.clipped
dEQP-VK.synchronization.fences
dEQP-VK.synchronization.semaphores
dEQP-VK.synchronization.events
diff --git a/external/vulkancts/README.md b/external/vulkancts/README.md
index 65561e9..7985148 100644
--- a/external/vulkancts/README.md
+++ b/external/vulkancts/README.md
@@ -134,6 +134,11 @@
--deqp-vk-device-id=<value>
+To speed up the conformance run on some platforms the following command line
+option may be used to disable frequent fflush() calls to the output logs:
+
+ --deqp-log-flush=disable
+
No other command line options are allowed.
### Win32
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
index a551680..3e146f6 100644
--- a/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
@@ -43,9 +43,10 @@
using std::vector;
using std::string;
-Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform,
- const vector<string>& enabledLayers,
- const vector<string>& enabledExtensions)
+Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform,
+ const vector<string>& enabledLayers,
+ const vector<string>& enabledExtensions,
+ const VkAllocationCallbacks* pAllocator)
{
vector<const char*> layerNamePtrs (enabledLayers.size());
vector<const char*> extensionNamePtrs (enabledExtensions.size());
@@ -79,12 +80,12 @@
for (size_t ndx = 0; ndx < enabledExtensions.size(); ++ndx)
extensionNamePtrs[ndx] = enabledExtensions[ndx].c_str();
- return createInstance(vkPlatform, &instanceInfo);
+ return createInstance(vkPlatform, &instanceInfo, pAllocator);
}
Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform)
{
- return createDefaultInstance(vkPlatform, vector<string>(), vector<string>());
+ return createDefaultInstance(vkPlatform, vector<string>(), vector<string>(), DE_NULL);
}
VkPhysicalDevice chooseDevice (const InstanceInterface& vkInstance, VkInstance instance, const tcu::CommandLine& cmdLine)
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
index 3b59e8b..123a815 100644
--- a/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
@@ -47,7 +47,8 @@
Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform);
Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform,
const std::vector<std::string>& enabledLayers,
- const std::vector<std::string>& enabledExtensions);
+ const std::vector<std::string>& enabledExtensions,
+ const VkAllocationCallbacks* pAllocator = DE_NULL);
VkPhysicalDevice chooseDevice (const InstanceInterface& vkInstance,
VkInstance instance,
diff --git a/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
index 6b36cce..f4dc86e 100644
--- a/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
+++ b/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
@@ -50,6 +50,8 @@
namespace
{
+static const deUint32 MAX_BUFFER_SIZE_DIVISOR = 16;
+
struct BufferCaseParameters
{
VkBufferUsageFlags usage;
@@ -97,16 +99,19 @@
tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
{
- const VkDevice vkDevice = m_context.getDevice();
- const DeviceInterface& vk = m_context.getDeviceInterface();
- Move<VkBuffer> testBuffer;
- VkMemoryRequirements memReqs;
- Move<VkDeviceMemory> memory;
- const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ const VkPhysicalDevice vkPhysicalDevice = m_context.getPhysicalDevice();
+ const InstanceInterface& vkInstance = m_context.getInstanceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ Move<VkBuffer> testBuffer;
+ VkMemoryRequirements memReqs;
+ Move<VkDeviceMemory> memory;
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
// Create buffer
{
- const VkBufferCreateInfo bufferParams =
+ VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
@@ -120,7 +125,7 @@
try
{
- testBuffer = createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
+ testBuffer = createBuffer(vk, vkDevice, &bufferParams);
}
catch (const vk::Error& error)
{
@@ -129,6 +134,27 @@
vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
+ const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits);
+ const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex];
+ const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex];
+ const VkDeviceSize maxBufferSize = memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
+ // If the requested size is too large, clamp it based on the selected heap size
+ if (size > maxBufferSize)
+ {
+ size = maxBufferSize;
+ bufferParams.size = size;
+ try
+ {
+ // allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
+ testBuffer = createBuffer(vk, vkDevice, &bufferParams);
+ }
+ catch (const vk::Error& error)
+ {
+ return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
+ }
+ vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
+ }
+
if (size > memReqs.size)
{
std::ostringstream errorMsg;
@@ -250,14 +276,10 @@
{
const VkPhysicalDevice vkPhysicalDevice = m_context.getPhysicalDevice();
const InstanceInterface& vkInstance = m_context.getInstanceInterface();
- const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
VkPhysicalDeviceProperties props;
vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
-
- const VkDeviceSize maxTestBufferSize = de::min((VkDeviceSize) props.limits.maxTexelBufferElements, memoryProperties.memoryHeaps[memoryProperties.memoryTypes[0].heapIndex].size / 16);
-
- testStatus = bufferCreateAndAllocTest(maxTestBufferSize);
+ testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
}
return testStatus;
diff --git a/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp b/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
index 68f9396..61cb205 100644
--- a/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
+++ b/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
@@ -60,7 +60,7 @@
#include <string>
#include <vector>
-// \todo Check bufferImageGranularity
+// \todo [2016-03-09 mika] Check bufferImageGranularity
using tcu::TestLog;
using tcu::Maybe;
@@ -145,7 +145,7 @@
USAGE_UNIFORM_TEXEL_BUFFER = (0x1u<<8),
USAGE_STORAGE_TEXEL_BUFFER = (0x1u<<9),
- // \todo This is probably almost impossible to do
+ // \todo [2016-03-09 mika] This is probably almost impossible to do
USAGE_INDIRECT_BUFFER = (0x1u<<10),
// Texture usage flags
@@ -753,7 +753,7 @@
{
const deUint8* data = (const deUint8*)data_;
- // \todo Optimize
+ // \todo [2016-03-09 mika] Optimize
for (size_t pos = 0; pos < size; pos++)
{
m_data[offset + pos] = data[pos];
@@ -763,7 +763,7 @@
void ReferenceMemory::setUndefined (size_t offset, size_t size)
{
- // \todo Optimize
+ // \todo [2016-03-09 mika] Optimize
for (size_t pos = 0; pos < size; pos++)
m_defined[(offset + pos) / 64] |= 0x1ull << ((offset + pos) % 64);
}
@@ -874,7 +874,7 @@
vk::VkDeviceSize bestW = de::max(maxTexelCount, maxTextureSize);
vk::VkDeviceSize bestH = maxTexelCount / bestW;
- // \todo Could probably be faster?
+ // \todo [2016-03-09 mika] Could probably be faster?
for (vk::VkDeviceSize w = 1; w * w < maxTexelCount && w < maxTextureSize && bestW * bestH * 4 < size; w++)
{
const vk::VkDeviceSize h = maxTexelCount / w;
@@ -898,7 +898,7 @@
DE_ASSERT((size % 4) == 0);
- // \todo Could probably be faster?
+ // \todo [2016-03-09 mika] Could probably be faster?
for (vk::VkDeviceSize w = 1; w < maxTextureSize && w < texelCount; w++)
{
const vk::VkDeviceSize h = texelCount / w;
@@ -2077,7 +2077,15 @@
class ImageTransition : public CmdCommand
{
public:
- ImageTransition (void) {}
+ ImageTransition (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses,
+
+ vk::VkImageLayout srcLayout,
+ vk::VkImageLayout dstLayout);
+
~ImageTransition (void) {}
const char* getName (void) const { return "ImageTransition"; }
@@ -2087,17 +2095,47 @@
void verify (VerifyContext& context, size_t);
private:
- vk::VkDeviceSize m_imageMemorySize;
+ const vk::VkPipelineStageFlags m_srcStages;
+ const vk::VkAccessFlags m_srcAccesses;
+ const vk::VkPipelineStageFlags m_dstStages;
+ const vk::VkAccessFlags m_dstAccesses;
+ const vk::VkImageLayout m_srcLayout;
+ const vk::VkImageLayout m_dstLayout;
+
+ vk::VkDeviceSize m_imageMemorySize;
};
+ImageTransition::ImageTransition (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses,
+
+ vk::VkImageLayout srcLayout,
+ vk::VkImageLayout dstLayout)
+ : m_srcStages (srcStages)
+ , m_srcAccesses (srcAccesses)
+ , m_dstStages (dstStages)
+ , m_dstAccesses (dstAccesses)
+ , m_srcLayout (srcLayout)
+ , m_dstLayout (dstLayout)
+{
+}
+
void ImageTransition::logSubmit (TestLog& log, size_t commandIndex) const
{
- log << TestLog::Message << commandIndex << ":" << getName() << " Use pipeline barrier to transition to VK_IMAGE_LAYOUT_GENERAL." << TestLog::EndMessage;
+ log << TestLog::Message << commandIndex << ":" << getName()
+ << " Image transition pipeline barrier"
+ << ", srcStages: " << vk::getPipelineStageFlagsStr(m_srcStages) << ", srcAccesses: " << vk::getAccessFlagsStr(m_srcAccesses)
+ << ", dstStages: " << vk::getPipelineStageFlagsStr(m_dstStages) << ", dstAccesses: " << vk::getAccessFlagsStr(m_dstAccesses)
+ << ", srcLayout: " << m_srcLayout << ", dstLayout: " << m_dstLayout << TestLog::EndMessage;
}
void ImageTransition::prepare (PrepareContext& context)
{
- context.setImageLayout(vk::VK_IMAGE_LAYOUT_GENERAL);
+ DE_ASSERT(context.getImageLayout() == vk::VK_IMAGE_LAYOUT_UNDEFINED || m_srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED || context.getImageLayout() == m_srcLayout);
+
+ context.setImageLayout(m_dstLayout);
m_imageMemorySize = context.getImageMemorySize();
}
@@ -2110,11 +2148,11 @@
vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
DE_NULL,
- ALL_ACCESSES,
- ALL_ACCESSES,
+ m_srcAccesses,
+ m_dstAccesses,
- context.getImageLayout(),
- vk::VK_IMAGE_LAYOUT_GENERAL,
+ m_srcLayout,
+ m_dstLayout,
vk::VK_QUEUE_FAMILY_IGNORED,
vk::VK_QUEUE_FAMILY_IGNORED,
@@ -2127,7 +2165,7 @@
}
};
- vkd.cmdPipelineBarrier(cmd, ALL_PIPELINE_STAGES, ALL_PIPELINE_STAGES, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
+ vkd.cmdPipelineBarrier(cmd, m_srcStages, m_dstStages, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
}
void ImageTransition::verify (VerifyContext& context, size_t)
@@ -4920,7 +4958,7 @@
OP_IMAGE_DESTROY,
OP_IMAGE_BINDMEMORY,
- OP_IMAGE_TRANSITION_TO_GENERAL,
+ OP_IMAGE_TRANSITION_LAYOUT,
OP_IMAGE_COPY_TO_BUFFER,
OP_IMAGE_COPY_FROM_BUFFER,
@@ -4954,63 +4992,60 @@
STAGE_RENDER_PASS
};
+vk::VkAccessFlags getWriteAccessFlags (void)
+{
+ return vk::VK_ACCESS_SHADER_WRITE_BIT
+ | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+ | vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
+ | vk::VK_ACCESS_TRANSFER_WRITE_BIT
+ | vk::VK_ACCESS_HOST_WRITE_BIT
+ | vk::VK_ACCESS_MEMORY_WRITE_BIT;
+}
+
bool isWriteAccess (vk::VkAccessFlagBits access)
{
- switch (access)
- {
-
- case vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT: return false;
- case vk::VK_ACCESS_INDEX_READ_BIT: return false;
- case vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: return false;
- case vk::VK_ACCESS_UNIFORM_READ_BIT: return false;
- case vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: return false;
- case vk::VK_ACCESS_SHADER_READ_BIT: return false;
- case vk::VK_ACCESS_SHADER_WRITE_BIT: return true;
- case vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: return false;
- case vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: return true;
- case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: return false;
- case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: return true;
- case vk::VK_ACCESS_TRANSFER_READ_BIT: return false;
- case vk::VK_ACCESS_TRANSFER_WRITE_BIT: return true;
- case vk::VK_ACCESS_HOST_READ_BIT: return false;
- case vk::VK_ACCESS_HOST_WRITE_BIT: return true;
- case vk::VK_ACCESS_MEMORY_READ_BIT: return false;
- case vk::VK_ACCESS_MEMORY_WRITE_BIT: return true;
-
- default:
- DE_FATAL("Unknown access");
- return true;
- }
+ return getWriteAccessFlags() & access;
}
class CacheState
{
public:
- CacheState (vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
+ CacheState (vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
- bool isValid (vk::VkPipelineStageFlagBits stage,
- vk::VkAccessFlagBits access) const;
+ bool isValid (vk::VkPipelineStageFlagBits stage,
+ vk::VkAccessFlagBits access) const;
- void perform (vk::VkPipelineStageFlagBits stage,
- vk::VkAccessFlagBits access);
+ void perform (vk::VkPipelineStageFlagBits stage,
+ vk::VkAccessFlagBits access);
- void submitCommandBuffer (void);
+ void submitCommandBuffer (void);
+ void waitForIdle (void);
- void getFullBarrier (vk::VkPipelineStageFlags& srcStages,
- vk::VkAccessFlags& srcAccesses,
- vk::VkPipelineStageFlags& dstStages,
- vk::VkAccessFlags& dstAccesses) const;
+ void getFullBarrier (vk::VkPipelineStageFlags& srcStages,
+ vk::VkAccessFlags& srcAccesses,
+ vk::VkPipelineStageFlags& dstStages,
+ vk::VkAccessFlags& dstAccesses) const;
- void barrier (vk::VkPipelineStageFlags srcStages,
- vk::VkAccessFlags srcAccesses,
- vk::VkPipelineStageFlags dstStages,
- vk::VkAccessFlags dstAccesses);
+ void barrier (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses);
- void fullBarrier (void);
+ void imageLayoutBarrier (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses);
+
+ void checkImageLayoutBarrier (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses);
// Everything is clean and there is no need for barriers
- bool isClean (void) const;
+ bool isClean (void) const;
+ vk::VkPipelineStageFlags getAllowedStages (void) const { return m_allowedStages; }
+ vk::VkAccessFlags getAllowedAcceses (void) const { return m_allowedAccesses; }
private:
// Limit which stages and accesses are used by the CacheState tracker
const vk::VkPipelineStageFlags m_allowedStages;
@@ -5019,6 +5054,8 @@
// [dstStage][srcStage] = srcAccesses
// In stage dstStage write srcAccesses from srcStage are not yet available
vk::VkAccessFlags m_unavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+ // Latest pipeline transition is not available in stage
+ bool m_unavailableLayoutTransition[PIPELINESTAGE_LAST];
// [dstStage] = dstAccesses
// In stage dstStage ops with dstAccesses are not yet visible
vk::VkAccessFlags m_invisibleOperations[PIPELINESTAGE_LAST];
@@ -5045,6 +5082,9 @@
// There are no incomplete read operations initially
m_incompleteOperations[dstStage] = 0;
+ // There are no incomplete layout transitions
+ m_unavailableLayoutTransition[dstStage] = false;
+
for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
{
const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5068,7 +5108,7 @@
const PipelineStage dstStage = pipelineStageFlagToPipelineStage(stage);
// Previous operations are not visible to access on stage
- if ((m_invisibleOperations[dstStage] & access) != 0)
+ if (m_unavailableLayoutTransition[dstStage] || (m_invisibleOperations[dstStage] & access) != 0)
return false;
if (isWriteAccess(access))
@@ -5120,6 +5160,21 @@
m_allowedAccesses);
}
+void CacheState::waitForIdle (void)
+{
+ // Make all writes available
+ barrier(m_allowedStages,
+ m_allowedAccesses & getWriteAccessFlags(),
+ m_allowedStages,
+ 0);
+
+ // Make all writes visible on device side
+ barrier(m_allowedStages,
+ 0,
+ m_allowedStages & (~vk::VK_PIPELINE_STAGE_HOST_BIT),
+ m_allowedAccesses);
+}
+
void CacheState::getFullBarrier (vk::VkPipelineStageFlags& srcStages,
vk::VkAccessFlags& srcAccesses,
vk::VkPipelineStageFlags& dstStages,
@@ -5165,6 +5220,14 @@
srcStages |= dstStage_;
srcAccesses |= m_unavailableWriteOperations[dstStage][srcStage];
}
+
+ if (m_unavailableLayoutTransition[dstStage] && !m_unavailableLayoutTransition[srcStage])
+ {
+ // Add dependency between srcStage and dstStage if layout transition has not completed in dstStage,
+ // but has completed in srcStage.
+ dstStages |= dstStage_;
+ srcStages |= dstStage_;
+ }
}
}
@@ -5174,6 +5237,108 @@
DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
}
+void CacheState::checkImageLayoutBarrier (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses)
+{
+ DE_ASSERT((srcStages & (~m_allowedStages)) == 0);
+ DE_ASSERT((srcAccesses & (~m_allowedAccesses)) == 0);
+ DE_ASSERT((dstStages & (~m_allowedStages)) == 0);
+ DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
+
+ DE_UNREF(srcStages);
+ DE_UNREF(srcAccesses);
+
+ DE_UNREF(dstStages);
+ DE_UNREF(dstAccesses);
+
+#if defined(DE_DEBUG)
+ // Check that all stages have completed before srcStages or are in srcStages.
+ {
+ vk::VkPipelineStageFlags completedStages = srcStages;
+
+ for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
+ {
+ const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+ if ((srcStage_ & srcStages) == 0)
+ continue;
+
+ completedStages |= (~m_incompleteOperations[srcStage]);
+ }
+
+ DE_ASSERT((completedStages & m_allowedStages) == m_allowedStages);
+ }
+
+ // Check that any write is available at least in one stage. Since all stages are complete even single flush is enough.
+ if ((getWriteAccessFlags() & m_allowedAccesses) != 0 && (srcAccesses & getWriteAccessFlags()) == 0)
+ {
+ bool anyWriteAvailable = false;
+
+ for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+ {
+ const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+ if ((dstStage_ & m_allowedStages) == 0)
+ continue;
+
+ for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+ {
+ const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+ if ((srcStage_ & m_allowedStages) == 0)
+ continue;
+
+ if (m_unavailableWriteOperations[dstStage][srcStage] != (getWriteAccessFlags() & m_allowedAccesses))
+ {
+ anyWriteAvailable = true;
+ break;
+ }
+ }
+ }
+
+ DE_ASSERT(anyWriteAvailable);
+ }
+#endif
+}
+
+void CacheState::imageLayoutBarrier (vk::VkPipelineStageFlags srcStages,
+ vk::VkAccessFlags srcAccesses,
+ vk::VkPipelineStageFlags dstStages,
+ vk::VkAccessFlags dstAccesses)
+{
+ checkImageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
+
+ for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+ {
+ const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+ if ((dstStage_ & m_allowedStages) == 0)
+ continue;
+
+ // All stages are incomplete after the barrier except each dstStage in it self.
+ m_incompleteOperations[dstStage] = m_allowedStages & (~dstStage_);
+
+ // All memory operations are invisible unless they are listed in dstAccess
+ m_invisibleOperations[dstStage] = m_allowedAccesses & (~dstAccesses);
+
+ // Layout transition is unavailable in stage unless it was listed in dstStages
+ m_unavailableLayoutTransition[dstStage]= (dstStage_ & dstStages) == 0;
+
+ for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+ {
+ const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+ if ((srcStage_ & m_allowedStages) == 0)
+ continue;
+
+ // All write operations are available after layout transition
+ m_unavailableWriteOperations[dstStage][srcStage] = 0;
+ }
+ }
+}
+
void CacheState::barrier (vk::VkPipelineStageFlags srcStages,
vk::VkAccessFlags srcAccesses,
vk::VkPipelineStageFlags dstStages,
@@ -5188,9 +5353,11 @@
{
vk::VkPipelineStageFlags oldIncompleteOperations[PIPELINESTAGE_LAST];
vk::VkAccessFlags oldUnavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+ bool oldUnavailableLayoutTransition[PIPELINESTAGE_LAST];
deMemcpy(oldIncompleteOperations, m_incompleteOperations, sizeof(oldIncompleteOperations));
deMemcpy(oldUnavailableWriteOperations, m_unavailableWriteOperations, sizeof(oldUnavailableWriteOperations));
+ deMemcpy(oldUnavailableLayoutTransition, m_unavailableLayoutTransition, sizeof(oldUnavailableLayoutTransition));
for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
{
@@ -5209,6 +5376,9 @@
// Stages that have completed before srcStage have also completed before dstStage
m_incompleteOperations[dstStage] &= oldIncompleteOperations[srcStage];
+ // Image layout transition in srcStage are now available in dstStage
+ m_unavailableLayoutTransition[dstStage] &= oldUnavailableLayoutTransition[srcStage];
+
for (vk::VkPipelineStageFlags sharedStage_ = 1; sharedStage_ <= m_allowedStages; sharedStage_ <<= 1)
{
const PipelineStage sharedStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)sharedStage_);
@@ -5273,6 +5443,10 @@
if (m_incompleteOperations[dstStage] != 0)
return false;
+ // Layout transition has not completed yet
+ if (m_unavailableLayoutTransition[dstStage])
+ return false;
+
for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
{
const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5289,34 +5463,6 @@
return true;
}
-void CacheState::fullBarrier (void)
-{
- for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
- {
- const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
-
- if ((dstStage_ & m_allowedStages) == 0)
- continue;
-
- // All stages have completed
- m_incompleteOperations[dstStage] = 0;
-
- // All operations are visible
- m_invisibleOperations[dstStage] = 0;
-
- for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
- {
- const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
-
- if ((srcStage_ & m_allowedStages) == 0)
- continue;
-
- // All writes are available
- m_unavailableWriteOperations[dstStage][srcStage] = 0;
- }
- }
-}
-
struct State
{
State (Usage usage, deUint32 seed)
@@ -5331,7 +5477,7 @@
, hasBoundBufferMemory (false)
, hasImage (false)
, hasBoundImageMemory (false)
- , imageHasGeneralLayout (false)
+ , imageLayout (vk::VK_IMAGE_LAYOUT_UNDEFINED)
, imageDefined (false)
, queueIdle (true)
, deviceIdle (true)
@@ -5339,27 +5485,27 @@
{
}
- Stage stage;
- CacheState cache;
- de::Random rng;
+ Stage stage;
+ CacheState cache;
+ de::Random rng;
- bool mapped;
- bool hostInvalidated;
- bool hostFlushed;
- bool memoryDefined;
+ bool mapped;
+ bool hostInvalidated;
+ bool hostFlushed;
+ bool memoryDefined;
- bool hasBuffer;
- bool hasBoundBufferMemory;
+ bool hasBuffer;
+ bool hasBoundBufferMemory;
- bool hasImage;
- bool hasBoundImageMemory;
- bool imageHasGeneralLayout;
- bool imageDefined;
+ bool hasImage;
+ bool hasBoundImageMemory;
+ vk::VkImageLayout imageLayout;
+ bool imageDefined;
- bool queueIdle;
- bool deviceIdle;
+ bool queueIdle;
+ bool deviceIdle;
- bool commandBufferIsEmpty;
+ bool commandBufferIsEmpty;
};
void getAvailableOps (const State& state, bool supportsBuffers, bool supportsImages, Usage usage, vector<Op>& ops)
@@ -5502,14 +5648,12 @@
if (state.hasBoundImageMemory)
{
- if (!state.imageHasGeneralLayout)
- {
- ops.push_back(OP_IMAGE_TRANSITION_TO_GENERAL);
- }
- else
+ ops.push_back(OP_IMAGE_TRANSITION_LAYOUT);
+
{
if (usage & USAGE_TRANSFER_DST
- && state.imageHasGeneralLayout
+ && (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+ || state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
&& state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT))
{
ops.push_back(OP_IMAGE_COPY_FROM_BUFFER);
@@ -5518,7 +5662,8 @@
}
if (usage & USAGE_TRANSFER_SRC
- && state.imageHasGeneralLayout
+ && (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+ || state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
&& state.imageDefined
&& state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT))
{
@@ -5529,7 +5674,7 @@
}
}
- // \todo Add other usages?
+ // \todo [2016-03-09 mika] Add other usages?
if (((usage & USAGE_VERTEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT))
|| ((usage & USAGE_INDEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_INDEX_READ_BIT)))
ops.push_back(OP_RENDERPASS_BEGIN);
@@ -5563,7 +5708,85 @@
DE_FATAL("Unknown stage");
}
-void applyOp (State& state, const Memory& memory, Op op)
+bool layoutSupportedByUsage (Usage usage, vk::VkImageLayout layout)
+{
+ switch (layout)
+ {
+ case vk::VK_IMAGE_LAYOUT_GENERAL:
+ return true;
+
+ case vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ return (usage & USAGE_COLOR_ATTACHMENT) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+ return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+ return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+ // \todo [2016-03-09 mika] Should include input attachment
+ return (usage & USAGE_TEXTURE_SAMPLED) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+ return (usage & USAGE_TRANSFER_SRC) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+ return (usage & USAGE_TRANSFER_DST) != 0;
+
+ case vk::VK_IMAGE_LAYOUT_PREINITIALIZED:
+ return true;
+
+ default:
+ DE_FATAL("Unknown layout");
+ return false;
+ }
+}
+
+vk::VkImageLayout getRandomNextLayout (de::Random& rng,
+ Usage usage,
+ vk::VkImageLayout previousLayout)
+{
+ const vk::VkImageLayout layouts[] =
+ {
+ vk::VK_IMAGE_LAYOUT_GENERAL,
+ vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+ vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ };
+ size_t possibleLayoutCount = 0;
+
+ for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+ {
+ const vk::VkImageLayout layout = layouts[layoutNdx];
+
+ if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+ possibleLayoutCount++;
+ }
+
+ size_t nextLayoutNdx = ((size_t)rng.getUint64()) % possibleLayoutCount;
+
+ for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+ {
+ const vk::VkImageLayout layout = layouts[layoutNdx];
+
+ if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+ {
+ if (nextLayoutNdx == 0)
+ return layout;
+ else
+ nextLayoutNdx--;
+ }
+ }
+
+ DE_FATAL("Unreachable");
+ return vk::VK_IMAGE_LAYOUT_UNDEFINED;
+}
+
+void applyOp (State& state, const Memory& memory, Op op, Usage usage)
{
switch (op)
{
@@ -5604,7 +5827,7 @@
state.memoryDefined = true;
state.imageDefined = false;
- state.imageHasGeneralLayout = false;
+ state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
state.rng.getUint32();
break;
@@ -5657,7 +5880,7 @@
state.hasImage = false;
state.hasBoundImageMemory = false;
- state.imageHasGeneralLayout = false;
+ state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
state.imageDefined = false;
break;
@@ -5669,20 +5892,58 @@
state.hasBoundImageMemory = true;
break;
- case OP_IMAGE_TRANSITION_TO_GENERAL:
+ case OP_IMAGE_TRANSITION_LAYOUT:
+ {
DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
DE_ASSERT(state.hasImage);
DE_ASSERT(state.hasBoundImageMemory);
- state.imageHasGeneralLayout = true;
+ // \todo [2016-03-09 mika] Support linear tiling and predefined data
+ const vk::VkImageLayout srcLayout = state.rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+ const vk::VkImageLayout dstLayout = getRandomNextLayout(state.rng, usage, srcLayout);
+
+ vk::VkPipelineStageFlags dirtySrcStages;
+ vk::VkAccessFlags dirtySrcAccesses;
+ vk::VkPipelineStageFlags dirtyDstStages;
+ vk::VkAccessFlags dirtyDstAccesses;
+
+ vk::VkPipelineStageFlags srcStages;
+ vk::VkAccessFlags srcAccesses;
+ vk::VkPipelineStageFlags dstStages;
+ vk::VkAccessFlags dstAccesses;
+
+ state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+ // Try masking some random bits
+ srcStages = dirtySrcStages;
+ srcAccesses = dirtySrcAccesses;
+
+ dstStages = state.cache.getAllowedStages() & state.rng.getUint32();
+ dstAccesses = state.cache.getAllowedAcceses() & state.rng.getUint32();
+
+ // If there are no bits in dst stage mask use all stages
+ dstStages = dstStages ? dstStages : state.cache.getAllowedStages();
+
+ if (!srcStages)
+ srcStages = dstStages;
+
+ if (srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
+ state.imageDefined = false;
+
+ state.commandBufferIsEmpty = false;
+ state.imageLayout = dstLayout;
state.memoryDefined = false;
+ state.cache.imageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
break;
+ }
case OP_QUEUE_WAIT_FOR_IDLE:
DE_ASSERT(state.stage == STAGE_HOST);
DE_ASSERT(!state.queueIdle);
state.queueIdle = true;
+
+ state.cache.waitForIdle();
break;
case OP_DEVICE_WAIT_FOR_IDLE:
@@ -5691,6 +5952,8 @@
state.queueIdle = true;
state.deviceIdle = true;
+
+ state.cache.waitForIdle();
break;
case OP_COMMAND_BUFFER_BEGIN:
@@ -5706,7 +5969,6 @@
state.stage = STAGE_HOST;
state.queueIdle = false;
state.deviceIdle = false;
- // \todo Should this set all device reads ready?
break;
case OP_BUFFER_COPY_FROM_BUFFER:
@@ -5722,7 +5984,7 @@
state.commandBufferIsEmpty = false;
state.memoryDefined = true;
state.imageDefined = false;
- state.imageHasGeneralLayout = false;
+ state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
state.cache.perform(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT);
break;
@@ -5872,7 +6134,8 @@
de::MovePtr<CmdCommand> createCmdCommand (de::Random& rng,
const State& state,
- Op op)
+ Op op,
+ Usage usage)
{
switch (op)
{
@@ -5884,7 +6147,42 @@
case OP_BUFFER_COPY_TO_IMAGE: return de::MovePtr<CmdCommand>(new BufferCopyToImage());
case OP_BUFFER_COPY_FROM_IMAGE: return de::MovePtr<CmdCommand>(new BufferCopyFromImage(rng.getUint32()));
- case OP_IMAGE_TRANSITION_TO_GENERAL: return de::MovePtr<CmdCommand>(new ImageTransition());
+ case OP_IMAGE_TRANSITION_LAYOUT:
+ {
+ DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
+ DE_ASSERT(state.hasImage);
+ DE_ASSERT(state.hasBoundImageMemory);
+
+ const vk::VkImageLayout srcLayout = rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+ const vk::VkImageLayout dstLayout = getRandomNextLayout(rng, usage, srcLayout);
+
+ vk::VkPipelineStageFlags dirtySrcStages;
+ vk::VkAccessFlags dirtySrcAccesses;
+ vk::VkPipelineStageFlags dirtyDstStages;
+ vk::VkAccessFlags dirtyDstAccesses;
+
+ vk::VkPipelineStageFlags srcStages;
+ vk::VkAccessFlags srcAccesses;
+ vk::VkPipelineStageFlags dstStages;
+ vk::VkAccessFlags dstAccesses;
+
+ state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+ // Try masking some random bits
+ srcStages = dirtySrcStages;
+ srcAccesses = dirtySrcAccesses;
+
+ dstStages = state.cache.getAllowedStages() & rng.getUint32();
+ dstAccesses = state.cache.getAllowedAcceses() & rng.getUint32();
+
+ // If there are no bits in dst stage mask use all stages
+ dstStages = dstStages ? dstStages : state.cache.getAllowedStages();
+
+ if (!srcStages)
+ srcStages = dstStages;
+
+ return de::MovePtr<CmdCommand>(new ImageTransition(srcStages, srcAccesses, dstStages, dstAccesses, srcLayout, dstLayout));
+ }
case OP_IMAGE_COPY_TO_BUFFER: return de::MovePtr<CmdCommand>(new ImageCopyToBuffer());
case OP_IMAGE_COPY_FROM_BUFFER: return de::MovePtr<CmdCommand>(new ImageCopyFromBuffer(rng.getUint32()));
@@ -5977,38 +6275,47 @@
size_t& opNdx,
size_t opCount)
{
- // \todo Exception safety
vector<RenderPassCommand*> commands;
- for (; opNdx < opCount; opNdx++)
+ try
{
- vector<Op> ops;
-
- getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
-
- DE_ASSERT(!ops.empty());
-
+ for (; opNdx < opCount; opNdx++)
{
- const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+ vector<Op> ops;
- if (op == OP_RENDERPASS_END)
+ getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+
+ DE_ASSERT(!ops.empty());
+
{
- break;
- }
- else
- {
- de::Random rng (state.rng);
+ const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
- commands.push_back(createRenderPassCommand(rng, state, op).release());
- applyOp(state, memory, op);
+ if (op == OP_RENDERPASS_END)
+ {
+ break;
+ }
+ else
+ {
+ de::Random rng (state.rng);
- DE_ASSERT(state.rng == rng);
+ commands.push_back(createRenderPassCommand(rng, state, op).release());
+ applyOp(state, memory, op, usage);
+
+ DE_ASSERT(state.rng == rng);
+ }
}
}
- }
- applyOp(state, memory, OP_RENDERPASS_END);
- return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
+ applyOp(state, memory, OP_RENDERPASS_END, usage);
+ return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
+ }
+ catch (...)
+ {
+ for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+ delete commands[commandNdx];
+
+ throw;
+ }
}
de::MovePtr<Command> createCmdCommands (const Memory& memory,
@@ -6018,48 +6325,57 @@
size_t& opNdx,
size_t opCount)
{
- // \todo Exception safety
vector<CmdCommand*> commands;
- for (; opNdx < opCount; opNdx++)
+ try
{
- vector<Op> ops;
-
- getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
-
- DE_ASSERT(!ops.empty());
-
+ for (; opNdx < opCount; opNdx++)
{
- const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+ vector<Op> ops;
- if (op == OP_COMMAND_BUFFER_END)
+ getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+
+ DE_ASSERT(!ops.empty());
+
{
- break;
- }
- else
- {
- // \note Command needs to known the state before the operation
- if (op == OP_RENDERPASS_BEGIN)
+ const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+
+ if (op == OP_COMMAND_BUFFER_END)
{
- applyOp(state, memory, op);
- commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+ break;
}
else
{
- de::Random rng (state.rng);
+ // \note Command needs to known the state before the operation
+ if (op == OP_RENDERPASS_BEGIN)
+ {
+ applyOp(state, memory, op, usage);
+ commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+ }
+ else
+ {
+ de::Random rng (state.rng);
- commands.push_back(createCmdCommand(rng, state, op).release());
- applyOp(state, memory, op);
+ commands.push_back(createCmdCommand(rng, state, op, usage).release());
+ applyOp(state, memory, op, usage);
- DE_ASSERT(state.rng == rng);
+ DE_ASSERT(state.rng == rng);
+ }
+
}
-
}
}
- }
- applyOp(state, memory, OP_COMMAND_BUFFER_END);
- return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
+ applyOp(state, memory, OP_COMMAND_BUFFER_END, usage);
+ return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
+ }
+ catch (...)
+ {
+ for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+ delete commands[commandNdx];
+
+ throw;
+ }
}
void createCommands (vector<Command*>& commands,
@@ -6088,7 +6404,7 @@
if (op == OP_COMMAND_BUFFER_BEGIN)
{
- applyOp(state, memory, op);
+ applyOp(state, memory, op, usage);
commands.push_back(createCmdCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
}
else
@@ -6096,7 +6412,7 @@
de::Random rng (state.rng);
commands.push_back(createHostCommand(op, rng, usage, sharingMode).release());
- applyOp(state, memory, op);
+ applyOp(state, memory, op, usage);
// Make sure that random generator is in sync
DE_ASSERT(state.rng == rng);
@@ -6319,7 +6635,7 @@
tcu::TestStatus MemoryTestInstance::iterate (void)
{
- // \todo Split different stages over multiple iterations
+ // \todo [2016-03-09 mika] Split different stages over multiple iterations
if (m_memoryTypeNdx < m_memoryProperties.memoryTypeCount)
{
TestLog& log = m_context.getTestContext().getLog();
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
index 6e6426c..0e731a2 100644
--- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
@@ -101,6 +101,18 @@
typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
}
+static void floorAll (vector<float>& values)
+{
+ for (size_t i = 0; i < values.size(); i++)
+ values[i] = deFloatFloor(values[i]);
+}
+
+static void floorAll (vector<Vec4>& values)
+{
+ for (size_t i = 0; i < values.size(); i++)
+ values[i] = floor(values[i]);
+}
+
struct CaseParameter
{
const char* name;
@@ -571,6 +583,9 @@
fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats1);
+
for (size_t ndx = 0; ndx < numElements; ++ndx)
outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
@@ -777,6 +792,9 @@
fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats);
+
for (size_t ndx = 0; ndx < numElements; ++ndx)
outputFloats[ndx] = inputFloats[ndx] + 7.5f;
@@ -1037,15 +1055,12 @@
fillRandomScalars(rnd, -300.f, 300.f, &inputFloats3[0], numElements);
fillRandomScalars(rnd, -300.f, 300.f, &inputFloats4[0], numElements);
-
- for (size_t ndx = 0; ndx < numElements; ++ndx)
- {
- inputFloats0[ndx] = deFloatFloor(inputFloats0[ndx]);
- inputFloats1[ndx] = deFloatFloor(inputFloats1[ndx]);
- inputFloats2[ndx] = deFloatFloor(inputFloats2[ndx]);
- inputFloats3[ndx] = deFloatFloor(inputFloats3[ndx]);
- inputFloats4[ndx] = deFloatFloor(inputFloats4[ndx]);
- }
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats0);
+ floorAll(inputFloats1);
+ floorAll(inputFloats2);
+ floorAll(inputFloats3);
+ floorAll(inputFloats4);
for (size_t ndx = 0; ndx < numElements; ++ndx)
outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
@@ -1396,6 +1411,9 @@
fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats);
+
for (size_t ndx = 0; ndx < numElements; ++ndx)
{
switch (ndx % 3)
@@ -1598,8 +1616,8 @@
fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
- for (size_t ndx = 0; ndx < numElements; ++ndx)
- inputFloats[ndx] = deFloatFloor(inputFloats[ndx]);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats);
for (size_t ndx = 0; ndx <= 50; ++ndx)
outputFloats[ndx] = -inputFloats[ndx];
@@ -2928,6 +2946,9 @@
fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats);
+
for (size_t ndx = 0; ndx < numElements; ++ndx)
outputFloats[ndx] = inputFloats[ndx] + (inputFloats[ndx] > 10.f ? 1.f : -1.f);
@@ -3020,6 +3041,9 @@
fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
+ // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+ floorAll(inputFloats);
+
for (size_t ndx = 0; ndx < numElements; ++ndx)
outputFloats[ndx] = inputFloats[ndx] + 10.f;
diff --git a/external/vulkancts/modules/vulkan/vktSynchronization.cpp b/external/vulkancts/modules/vulkan/vktSynchronization.cpp
index e6cdbc2..695d17b 100644
--- a/external/vulkancts/modules/vulkan/vktSynchronization.cpp
+++ b/external/vulkancts/modules/vulkan/vktSynchronization.cpp
@@ -209,7 +209,7 @@
range.offset = newMemory->getOffset();
range.size = bufferParameters.size;
- deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, bufferParameters.size);
+ deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, (size_t)bufferParameters.size);
VK_CHECK(deviceInterface.flushMappedMemoryRanges(device, 1, &range));
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
index 29b8973..42c0553 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
@@ -45,6 +45,7 @@
#include "vkTypeUtil.hpp"
#include "vkWsiPlatform.hpp"
#include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuFormatUtil.hpp"
@@ -108,9 +109,10 @@
}
}
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
- const Extensions& supportedExtensions,
- Type wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
+ const Extensions& supportedExtensions,
+ Type wsiType,
+ const VkAllocationCallbacks* pAllocator = DE_NULL)
{
vector<string> extensions;
@@ -119,7 +121,7 @@
checkAllSupported(supportedExtensions, extensions);
- return createDefaultInstance(vkp, vector<string>(), extensions);
+ return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
}
struct InstanceHelper
@@ -128,12 +130,13 @@
Unique<VkInstance> instance;
const InstanceDriver vki;
- InstanceHelper (Context& context, Type wsiType)
+ InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
: supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
DE_NULL))
, instance (createInstanceWithWsi(context.getPlatformInterface(),
supportedExtensions,
- wsiType))
+ wsiType,
+ pAllocator))
, vki (context.getPlatformInterface(), *instance)
{}
};
@@ -196,6 +199,89 @@
return tcu::TestStatus::pass("Creating surface succeeded");
}
+tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
+{
+ AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
+ tcu::TestLog& log = context.getTestContext().getLog();
+
+ {
+ const InstanceHelper instHelper (context, wsiType, allocationRecorder.getCallbacks());
+ const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
+ *instHelper.instance,
+ wsiType,
+ *native.display,
+ *native.window,
+ allocationRecorder.getCallbacks()));
+
+ if (!validateAndLog(log,
+ allocationRecorder,
+ (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
+ (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+ return tcu::TestStatus::fail("Detected invalid system allocation callback");
+ }
+
+ if (!validateAndLog(log, allocationRecorder, 0u))
+ return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+ if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
+ return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+ else
+ return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
+}
+
+tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
+{
+ tcu::TestLog& log = context.getTestContext().getLog();
+
+ for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
+ {
+ AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
+ DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(), numPassingAllocs);
+ bool gotOOM = false;
+
+ log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+ try
+ {
+ const InstanceHelper instHelper (context, wsiType, failingAllocator.getCallbacks());
+ const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
+ *instHelper.instance,
+ wsiType,
+ *native.display,
+ *native.window,
+ failingAllocator.getCallbacks()));
+
+ if (!validateAndLog(log,
+ allocationRecorder,
+ (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
+ (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+ return tcu::TestStatus::fail("Detected invalid system allocation callback");
+ }
+ catch (const OutOfMemoryError& e)
+ {
+ log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+ gotOOM = true;
+ }
+
+ if (!validateAndLog(log, allocationRecorder, 0u))
+ return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+ if (!gotOOM)
+ {
+ log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+ if (numPassingAllocs == 0)
+ return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+ else
+ return tcu::TestStatus::pass("OOM simulation completed");
+ }
+ }
+
+ return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
+}
+
deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
{
deUint32 numFamilies = 0;
@@ -524,11 +610,13 @@
{
const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
- addFunctionCase(testGroup, "create", "Create surface", createSurfaceTest, wsiType);
- addFunctionCase(testGroup, "query_support", "Query surface support", querySurfaceSupportTest, wsiType);
- addFunctionCase(testGroup, "query_capabilities", "Query surface capabilities", querySurfaceCapabilitiesTest, wsiType);
- addFunctionCase(testGroup, "query_formats", "Query surface formats", querySurfaceFormatsTest, wsiType);
- addFunctionCase(testGroup, "query_present_modes", "Query surface present modes", querySurfacePresentModesTest, wsiType);
+ addFunctionCase(testGroup, "create", "Create surface", createSurfaceTest, wsiType);
+ addFunctionCase(testGroup, "create_custom_allocator", "Create surface with custom allocator", createSurfaceCustomAllocatorTest, wsiType);
+ addFunctionCase(testGroup, "create_simulate_oom", "Create surface with simulating OOM", createSurfaceSimulateOOMTest, wsiType);
+ addFunctionCase(testGroup, "query_support", "Query surface support", querySurfaceSupportTest, wsiType);
+ addFunctionCase(testGroup, "query_capabilities", "Query surface capabilities", querySurfaceCapabilitiesTest, wsiType);
+ addFunctionCase(testGroup, "query_formats", "Query surface formats", querySurfaceFormatsTest, wsiType);
+ addFunctionCase(testGroup, "query_present_modes", "Query surface present modes", querySurfacePresentModesTest, wsiType);
if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
addFunctionCase(testGroup, "initial_size", "Create surface with initial window size set", createSurfaceInitialSizeTest, wsiType);
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
index 5f977b8..1342955 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
@@ -45,6 +45,7 @@
#include "vkTypeUtil.hpp"
#include "vkWsiPlatform.hpp"
#include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuFormatUtil.hpp"
@@ -89,9 +90,10 @@
}
}
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
- const Extensions& supportedExtensions,
- Type wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
+ const Extensions& supportedExtensions,
+ Type wsiType,
+ const VkAllocationCallbacks* pAllocator = DE_NULL)
{
vector<string> extensions;
@@ -100,7 +102,7 @@
checkAllSupported(supportedExtensions, extensions);
- return createDefaultInstance(vkp, vector<string>(), extensions);
+ return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
}
VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
@@ -110,10 +112,11 @@
return features;
}
-Move<VkDevice> createDeviceWithWsi (const InstanceInterface& vki,
- VkPhysicalDevice physicalDevice,
- const Extensions& supportedExtensions,
- const deUint32 queueFamilyIndex)
+Move<VkDevice> createDeviceWithWsi (const InstanceInterface& vki,
+ VkPhysicalDevice physicalDevice,
+ const Extensions& supportedExtensions,
+ const deUint32 queueFamilyIndex,
+ const VkAllocationCallbacks* pAllocator = DE_NULL)
{
const float queuePriorities[] = { 1.0f };
const VkDeviceQueueCreateInfo queueInfos[] =
@@ -149,7 +152,7 @@
TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
}
- return createDevice(vki, physicalDevice, &deviceParams, (const VkAllocationCallbacks*)DE_NULL);
+ return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
}
deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
@@ -191,12 +194,13 @@
const Unique<VkInstance> instance;
const InstanceDriver vki;
- InstanceHelper (Context& context, Type wsiType)
+ InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
: supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
DE_NULL))
, instance (createInstanceWithWsi(context.getPlatformInterface(),
supportedExtensions,
- wsiType))
+ wsiType,
+ pAllocator))
, vki (context.getPlatformInterface(), *instance)
{}
};
@@ -216,13 +220,18 @@
const DeviceDriver vkd;
const VkQueue queue;
- DeviceHelper (Context& context, const InstanceInterface& vki, VkInstance instance, VkSurfaceKHR surface)
+ DeviceHelper (Context& context,
+ const InstanceInterface& vki,
+ VkInstance instance,
+ VkSurfaceKHR surface,
+ const VkAllocationCallbacks* pAllocator = DE_NULL)
: physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
, queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
, device (createDeviceWithWsi(vki,
physicalDevice,
enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
- queueFamilyIndex))
+ queueFamilyIndex,
+ pAllocator))
, vkd (vki, *device)
, queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
{
@@ -572,6 +581,75 @@
return tcu::TestStatus::pass("Creating swapchain succeeded");
}
+tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
+{
+ tcu::TestLog& log = context.getTestContext().getLog();
+
+ // \note This is a little counter-intuitive order (iterating on callback count until all cases pass)
+ // but since cases depend on what device reports, it is the only easy way. In practice
+ // we should see same number of total callbacks (and executed code) regardless of the
+ // loop order.
+
+ for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 16*1024u; ++numPassingAllocs)
+ {
+ AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
+ DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(), numPassingAllocs);
+ bool gotOOM = false;
+
+ log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+ try
+ {
+ const InstanceHelper instHelper (context, params.wsiType, failingAllocator.getCallbacks());
+ const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
+ *instHelper.instance,
+ params.wsiType,
+ *native.display,
+ *native.window,
+ failingAllocator.getCallbacks()));
+ const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
+ const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
+
+ for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+ {
+ VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
+
+ curParams.surface = *surface;
+ curParams.queueFamilyIndexCount = 1u;
+ curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
+
+ context.getTestContext().getLog()
+ << TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << TestLog::EndMessage;
+
+ {
+ const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
+ }
+ }
+ }
+ catch (const OutOfMemoryError& e)
+ {
+ log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+ gotOOM = true;
+ }
+
+ if (!validateAndLog(log, allocationRecorder, 0u))
+ return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+ if (!gotOOM)
+ {
+ log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+ if (numPassingAllocs == 0)
+ return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+ else
+ return tcu::TestStatus::pass("OOM simulation completed");
+ }
+ }
+
+ return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
+}
+
struct GroupParameters
{
typedef FunctionInstance1<TestParameters>::Function Function;
@@ -604,7 +682,8 @@
void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
{
- addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+ addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+ addTestGroup(testGroup, "simulate_oom", "Simulate OOM using callbacks during swapchain construction", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
}
} // wsi
diff --git a/framework/common/tcuCommandLine.cpp b/framework/common/tcuCommandLine.cpp
index b41ef7b..ba267d5 100644
--- a/framework/common/tcuCommandLine.cpp
+++ b/framework/common/tcuCommandLine.cpp
@@ -84,6 +84,7 @@
DE_DECLARE_COMMAND_LINE_OPT(LogShaderSources, bool);
DE_DECLARE_COMMAND_LINE_OPT(TestOOM, bool);
DE_DECLARE_COMMAND_LINE_OPT(VKDeviceID, int);
+DE_DECLARE_COMMAND_LINE_OPT(LogFlush, bool);
static void parseIntList (const char* src, std::vector<int>* dst)
{
@@ -168,7 +169,8 @@
<< Option<VKDeviceID> (DE_NULL, "deqp-vk-device-id", "Vulkan device ID (IDs start from 1)", "1")
<< Option<LogImages> (DE_NULL, "deqp-log-images", "Enable or disable logging of result images", s_enableNames, "enable")
<< Option<LogShaderSources> (DE_NULL, "deqp-log-shader-sources", "Enable or disable logging of shader sources", s_enableNames, "enable")
- << Option<TestOOM> (DE_NULL, "deqp-test-oom", "Run tests that exhaust memory on purpose", s_enableNames, TEST_OOM_DEFAULT);
+ << Option<TestOOM> (DE_NULL, "deqp-test-oom", "Run tests that exhaust memory on purpose", s_enableNames, TEST_OOM_DEFAULT)
+ << Option<LogFlush> (DE_NULL, "deqp-log-flush", "Enable or disable log file fflush", s_enableNames, "enable");
}
void registerLegacyOptions (de::cmdline::Parser& parser)
@@ -725,6 +727,9 @@
if (!m_cmdLine.getOption<opt::LogShaderSources>())
m_logFlags |= QP_TEST_LOG_EXCLUDE_SHADER_SOURCES;
+ if (!m_cmdLine.getOption<opt::LogFlush>())
+ m_logFlags |= QP_TEST_LOG_NO_FLUSH;
+
if ((m_cmdLine.hasOption<opt::CasePath>()?1:0) +
(m_cmdLine.hasOption<opt::CaseList>()?1:0) +
(m_cmdLine.hasOption<opt::CaseListFile>()?1:0) +
diff --git a/framework/common/tcuTestHierarchyUtil.cpp b/framework/common/tcuTestHierarchyUtil.cpp
index dc21619..34882eb 100644
--- a/framework/common/tcuTestHierarchyUtil.cpp
+++ b/framework/common/tcuTestHierarchyUtil.cpp
@@ -146,7 +146,7 @@
if (!file)
throw Exception("Failed to open " + filename);
- writer = qpXmlWriter_createFileWriter(file, DE_FALSE);
+ writer = qpXmlWriter_createFileWriter(file, DE_FALSE, DE_FALSE);
if (!writer)
throw Exception("XML writer creation failed");
diff --git a/framework/qphelper/qpTestLog.c b/framework/qphelper/qpTestLog.c
index 26c7923..327e232 100644
--- a/framework/qphelper/qpTestLog.c
+++ b/framework/qphelper/qpTestLog.c
@@ -350,7 +350,7 @@
}
log->flags = flags;
- log->writer = qpXmlWriter_createFileWriter(log->outputFile, 0);
+ log->writer = qpXmlWriter_createFileWriter(log->outputFile, 0, !(flags & QP_TEST_LOG_NO_FLUSH));
log->lock = deMutex_create(DE_NULL);
log->isSessionOpen = DE_FALSE;
log->isCaseOpen = DE_FALSE;
@@ -419,7 +419,8 @@
/* Flush XML and write out #beginTestCaseResult. */
qpXmlWriter_flush(log->writer);
fprintf(log->outputFile, "\n#beginTestCaseResult %s\n", testCasePath);
- qpTestLog_flushFile(log);
+ if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+ qpTestLog_flushFile(log);
log->isCaseOpen = DE_TRUE;
@@ -473,7 +474,8 @@
/* Flush XML and write #endTestCaseResult. */
qpXmlWriter_flush(log->writer);
fprintf(log->outputFile, "\n#endTestCaseResult\n");
- qpTestLog_flushFile(log);
+ if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+ qpTestLog_flushFile(log);
log->isCaseOpen = DE_FALSE;
diff --git a/framework/qphelper/qpTestLog.h b/framework/qphelper/qpTestLog.h
index aa74fa7..f12454f 100644
--- a/framework/qphelper/qpTestLog.h
+++ b/framework/qphelper/qpTestLog.h
@@ -133,7 +133,8 @@
typedef enum qpTestLogFlag_e
{
QP_TEST_LOG_EXCLUDE_IMAGES = (1<<0), /*!< Do not log images. This reduces log size considerably. */
- QP_TEST_LOG_EXCLUDE_SHADER_SOURCES = (1<<1) /*!< Do not log shader sources. Helps to reduce log size further. */
+ QP_TEST_LOG_EXCLUDE_SHADER_SOURCES = (1<<1), /*!< Do not log shader sources. Helps to reduce log size further. */
+ QP_TEST_LOG_NO_FLUSH = (1<<2) /*!< Do not do a fflush after writing the log. */
} qpTestLogFlag;
/* Shader type. */
diff --git a/framework/qphelper/qpXmlWriter.c b/framework/qphelper/qpXmlWriter.c
index 6921dab..97ee987 100644
--- a/framework/qphelper/qpXmlWriter.c
+++ b/framework/qphelper/qpXmlWriter.c
@@ -36,6 +36,7 @@
struct qpXmlWriter_s
{
FILE* outputFile;
+ deBool flushAfterWrite;
deBool xmlPrevIsStartElement;
deBool xmlIsWriting;
@@ -114,12 +115,13 @@
}
} while (!isEOS);
- fflush(writer->outputFile);
+ if (writer->flushAfterWrite)
+ fflush(writer->outputFile);
DE_ASSERT(d == &buf[0]); /* buffer must be empty */
return DE_TRUE;
}
-qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression)
+qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression, deBool flushAfterWrite)
{
qpXmlWriter* writer = (qpXmlWriter*)deCalloc(sizeof(qpXmlWriter));
if (!writer)
@@ -128,6 +130,7 @@
DE_UNREF(useCompression); /* no compression supported. */
writer->outputFile = outputFile;
+ writer->flushAfterWrite = flushAfterWrite;
return writer;
}
diff --git a/framework/qphelper/qpXmlWriter.h b/framework/qphelper/qpXmlWriter.h
index ebba428..bb63bde 100644
--- a/framework/qphelper/qpXmlWriter.h
+++ b/framework/qphelper/qpXmlWriter.h
@@ -85,9 +85,10 @@
* \brief Create a file based XML Writer instance
* \param fileName Name of the file
* \param useCompression Set to DE_TRUE to use compression, if supported by implementation
+ * \param flushAfterWrite Set to DE_TRUE to call fflush after writing each XML token
* \return qpXmlWriter instance, or DE_NULL if cannot create file
*//*--------------------------------------------------------------------*/
-qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression);
+qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression, deBool flushAfterWrite);
/*--------------------------------------------------------------------*//*!
* \brief XML Writer instance