framework/delibs/debase/deRandom.c \
framework/delibs/debase/deString.c \
framework/delibs/debase/deSha1.c \
+ framework/delibs/decpp/deAppendList.cpp \
framework/delibs/decpp/deArrayBuffer.cpp \
framework/delibs/decpp/deArrayUtil.cpp \
framework/delibs/decpp/deBlockBuffer.cpp \
Push constants
--------------
-TODO
-
[source,c]
----
void VKAPI vkCmdPushConstants(
const void* values);
----
+ * Range size, including verify various size of a single range from minimum to maximum
+ * Range count, including verify all the valid shader stages
+ * Data update, including verify a sub-range update, multiple times of updates
+
+ ? Invalid usages specified in spec NOT tested
+
GPU timestamps
--------------
self.postExtract(dstPath)
class GitRepo (Source):
- def __init__(self, url, revision, baseDir, extractDir = "src"):
+ def __init__(self, url, revision, baseDir, extractDir = "src", postCheckout = None):
Source.__init__(self, baseDir, extractDir)
- self.url = url
- self.revision = revision
+ self.url = url
+ self.revision = revision
+ self.postCheckout = postCheckout
def update (self):
fullDstPath = os.path.join(EXTERNAL_DIR, self.baseDir, self.extractDir)
try:
execute(["git", "fetch", self.url, "+refs/heads/*:refs/remotes/origin/*"])
execute(["git", "checkout", self.revision])
+
+ if self.postCheckout:
+ self.postCheckout(fullDstPath)
finally:
popWorkingDir()
shutil.copy(os.path.join(path, "scripts", "pnglibconf.h.prebuilt"),
os.path.join(path, "pnglibconf.h"))
+def postCheckoutGlslang (path):
+ srcPath = os.path.join(path, "SPIRV", "SpvBuilder.cpp");
+ origSrc = readFile(srcPath)
+ patched = origSrc.replace("exit(1)", "throw std::runtime_error(fun)")
+ writeFile(srcPath, patched)
+
PACKAGES = [
SourcePackage(
"http://zlib.net/zlib-1.2.8.tar.gz",
"spirv-tools"),
GitRepo(
"git@gitlab.khronos.org:GLSL/glslang.git",
- "9e1d1465801ace8edd95c951a3d4a9ada75306ed",
- "glslang"),
+ "41daec718f4868d956ca7d339a15aebe65879442",
+ "glslang",
+ postCheckout = postCheckoutGlslang),
]
def parseArgs ():
vkImageUtil.hpp
vkTypeUtil.cpp
vkTypeUtil.hpp
+ vkAllocationCallbackUtil.cpp
+ vkAllocationCallbackUtil.hpp
)
set(VKUTIL_LIBS
--- /dev/null
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Memory allocation callback utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkAllocationCallbackUtil.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuTestLog.hpp"
+#include "deSTLUtil.hpp"
+#include "deMemory.h"
+
+#include <map>
+
+namespace vk
+{
+
+// System default allocator
+
+static VKAPI_ATTR void* VKAPI_CALL systemAllocate (void*, size_t size, size_t alignment, VkSystemAllocationScope)
+{
+ if (size > 0)
+ return deAlignedMalloc(size, (deUint32)alignment);
+ else
+ return DE_NULL;
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemFree (void*, void* pMem)
+{
+ deAlignedFree(pMem);
+}
+
+static VKAPI_ATTR void* VKAPI_CALL systemReallocate (void*, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope)
+{
+ return deAlignedRealloc(pOriginal, size, alignment);
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemInternalAllocationNotification (void*, size_t, VkInternalAllocationType, VkSystemAllocationScope)
+{
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemInternalFreeNotification (void*, size_t, VkInternalAllocationType, VkSystemAllocationScope)
+{
+}
+
+static const VkAllocationCallbacks s_systemAllocator =
+{
+ DE_NULL, // pUserData
+ systemAllocate,
+ systemReallocate,
+ systemFree,
+ systemInternalAllocationNotification,
+ systemInternalFreeNotification,
+};
+
+const VkAllocationCallbacks* getSystemAllocator (void)
+{
+ return &s_systemAllocator;
+}
+
+// AllocationCallbacks
+
+static VKAPI_ATTR void* VKAPI_CALL allocationCallback (void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ return reinterpret_cast<AllocationCallbacks*>(pUserData)->allocate(size, alignment, allocationScope);
+}
+
+static VKAPI_ATTR void* VKAPI_CALL reallocationCallback (void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ return reinterpret_cast<AllocationCallbacks*>(pUserData)->reallocate(pOriginal, size, alignment, allocationScope);
+}
+
+static VKAPI_ATTR void VKAPI_CALL freeCallback (void* pUserData, void* pMem)
+{
+ reinterpret_cast<AllocationCallbacks*>(pUserData)->free(pMem);
+}
+
+static VKAPI_ATTR void VKAPI_CALL internalAllocationNotificationCallback (void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ reinterpret_cast<AllocationCallbacks*>(pUserData)->notifyInternalAllocation(size, allocationType, allocationScope);
+}
+
+static VKAPI_ATTR void VKAPI_CALL internalFreeNotificationCallback (void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ reinterpret_cast<AllocationCallbacks*>(pUserData)->notifyInternalFree(size, allocationType, allocationScope);
+}
+
+static VkAllocationCallbacks makeCallbacks (AllocationCallbacks* object)
+{
+ const VkAllocationCallbacks callbacks =
+ {
+ reinterpret_cast<void*>(object),
+ allocationCallback,
+ reallocationCallback,
+ freeCallback,
+ internalAllocationNotificationCallback,
+ internalFreeNotificationCallback
+ };
+ return callbacks;
+}
+
+AllocationCallbacks::AllocationCallbacks (void)
+ : m_callbacks(makeCallbacks(this))
+{
+}
+
+AllocationCallbacks::~AllocationCallbacks (void)
+{
+}
+
+// AllocationCallbackRecord
+
+AllocationCallbackRecord AllocationCallbackRecord::allocation (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr)
+{
+ AllocationCallbackRecord record;
+
+ record.type = TYPE_ALLOCATION;
+ record.data.allocation.size = size;
+ record.data.allocation.alignment = alignment;
+ record.data.allocation.scope = scope;
+ record.data.allocation.returnedPtr = returnedPtr;
+
+ return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::reallocation (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr)
+{
+ AllocationCallbackRecord record;
+
+ record.type = TYPE_REALLOCATION;
+ record.data.reallocation.original = original;
+ record.data.reallocation.size = size;
+ record.data.reallocation.alignment = alignment;
+ record.data.reallocation.scope = scope;
+ record.data.reallocation.returnedPtr = returnedPtr;
+
+ return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::free (void* mem)
+{
+ AllocationCallbackRecord record;
+
+ record.type = TYPE_FREE;
+ record.data.free.mem = mem;
+
+ return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::internalAllocation (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope)
+{
+ AllocationCallbackRecord record;
+
+ record.type = TYPE_INTERNAL_ALLOCATION;
+ record.data.internalAllocation.size = size;
+ record.data.internalAllocation.type = type;
+ record.data.internalAllocation.scope = scope;
+
+ return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::internalFree (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope)
+{
+ AllocationCallbackRecord record;
+
+ record.type = TYPE_INTERNAL_FREE;
+ record.data.internalAllocation.size = size;
+ record.data.internalAllocation.type = type;
+ record.data.internalAllocation.scope = scope;
+
+ return record;
+}
+
+// ChainedAllocator
+
+ChainedAllocator::ChainedAllocator (const VkAllocationCallbacks* nextAllocator)
+ : m_nextAllocator(nextAllocator)
+{
+}
+
+ChainedAllocator::~ChainedAllocator (void)
+{
+}
+
+void* ChainedAllocator::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ return m_nextAllocator->pfnAllocation(m_nextAllocator->pUserData, size, alignment, allocationScope);
+}
+
+void* ChainedAllocator::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ return m_nextAllocator->pfnReallocation(m_nextAllocator->pUserData, original, size, alignment, allocationScope);
+}
+
+void ChainedAllocator::free (void* mem)
+{
+ m_nextAllocator->pfnFree(m_nextAllocator->pUserData, mem);
+}
+
+void ChainedAllocator::notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ m_nextAllocator->pfnInternalAllocation(m_nextAllocator->pUserData, size, allocationType, allocationScope);
+}
+
+void ChainedAllocator::notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ m_nextAllocator->pfnInternalFree(m_nextAllocator->pUserData, size, allocationType, allocationScope);
+}
+
+// AllocationCallbackRecorder
+
+AllocationCallbackRecorder::AllocationCallbackRecorder (const VkAllocationCallbacks* allocator, deUint32 callCountHint)
+ : ChainedAllocator (allocator)
+ , m_records (callCountHint)
+{
+}
+
+AllocationCallbackRecorder::~AllocationCallbackRecorder (void)
+{
+}
+
+void* AllocationCallbackRecorder::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ void* const ptr = ChainedAllocator::allocate(size, alignment, allocationScope);
+
+ m_records.append(AllocationCallbackRecord::allocation(size, alignment, allocationScope, ptr));
+
+ return ptr;
+}
+
+void* AllocationCallbackRecorder::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ void* const ptr = ChainedAllocator::reallocate(original, size, alignment, allocationScope);
+
+ m_records.append(AllocationCallbackRecord::reallocation(original, size, alignment, allocationScope, ptr));
+
+ return ptr;
+}
+
+void AllocationCallbackRecorder::free (void* mem)
+{
+ ChainedAllocator::free(mem);
+
+ m_records.append(AllocationCallbackRecord::free(mem));
+}
+
+void AllocationCallbackRecorder::notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ ChainedAllocator::notifyInternalAllocation(size, allocationType, allocationScope);
+
+ m_records.append(AllocationCallbackRecord::internalAllocation(size, allocationType, allocationScope));
+}
+
+void AllocationCallbackRecorder::notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ ChainedAllocator::notifyInternalFree(size, allocationType, allocationScope);
+
+ m_records.append(AllocationCallbackRecord::internalFree(size, allocationType, allocationScope));
+}
+
+// DeterministicFailAllocator
+
+DeterministicFailAllocator::DeterministicFailAllocator (const VkAllocationCallbacks* allocator, deUint32 numPassingAllocs)
+ : ChainedAllocator (allocator)
+ , m_numPassingAllocs(numPassingAllocs)
+ , m_allocationNdx (0)
+{
+}
+
+DeterministicFailAllocator::~DeterministicFailAllocator (void)
+{
+}
+
+void* DeterministicFailAllocator::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ if (deAtomicIncrementUint32(&m_allocationNdx) <= m_numPassingAllocs)
+ return ChainedAllocator::allocate(size, alignment, allocationScope);
+ else
+ return DE_NULL;
+}
+
+void* DeterministicFailAllocator::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ if (deAtomicIncrementUint32(&m_allocationNdx) <= m_numPassingAllocs)
+ return ChainedAllocator::reallocate(original, size, alignment, allocationScope);
+ else
+ return DE_NULL;
+}
+
+// Utils
+
+AllocationCallbackValidationResults::AllocationCallbackValidationResults (void)
+{
+ deMemset(internalAllocationTotal, 0, sizeof(internalAllocationTotal));
+}
+
+void AllocationCallbackValidationResults::clear (void)
+{
+ liveAllocations.clear();
+ violations.clear();
+ deMemset(internalAllocationTotal, 0, sizeof(internalAllocationTotal));
+}
+
+namespace
+{
+
+struct AllocationSlot
+{
+ AllocationCallbackRecord record;
+ bool isLive;
+
+ AllocationSlot (void)
+ : isLive (false)
+ {}
+
+ AllocationSlot (const AllocationCallbackRecord& record_, bool isLive_)
+ : record (record_)
+ , isLive (isLive_)
+ {}
+};
+
+size_t getAlignment (const AllocationCallbackRecord& record)
+{
+ if (record.type == AllocationCallbackRecord::TYPE_ALLOCATION)
+ return record.data.allocation.alignment;
+ else if (record.type == AllocationCallbackRecord::TYPE_REALLOCATION)
+ return record.data.reallocation.alignment;
+ else
+ {
+ DE_ASSERT(false);
+ return 0;
+ }
+}
+
+} // anonymous
+
+void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results)
+{
+ std::vector<AllocationSlot> allocations;
+ std::map<void*, size_t> ptrToSlotIndex;
+
+ DE_ASSERT(results->liveAllocations.empty() && results->violations.empty());
+
+ for (AllocationCallbackRecorder::RecordIterator callbackIter = recorder.getRecordsBegin();
+ callbackIter != recorder.getRecordsEnd();
+ ++callbackIter)
+ {
+ const AllocationCallbackRecord& record = *callbackIter;
+
+ // Validate scope
+ {
+ const VkSystemAllocationScope* const scopePtr = record.type == AllocationCallbackRecord::TYPE_ALLOCATION ? &record.data.allocation.scope
+ : record.type == AllocationCallbackRecord::TYPE_REALLOCATION ? &record.data.reallocation.scope
+ : record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION ? &record.data.internalAllocation.scope
+ : record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE ? &record.data.internalAllocation.scope
+ : DE_NULL;
+
+ if (scopePtr && !de::inBounds(*scopePtr, (VkSystemAllocationScope)0, VK_SYSTEM_ALLOCATION_SCOPE_LAST))
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_ALLOCATION_SCOPE));
+ }
+
+ // Validate alignment
+ if (record.type == AllocationCallbackRecord::TYPE_ALLOCATION ||
+ record.type == AllocationCallbackRecord::TYPE_REALLOCATION)
+ {
+ if (!deIsPowerOfTwoSize(getAlignment(record)))
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_ALIGNMENT));
+ }
+
+ // Validate actual allocation behavior
+ switch (record.type)
+ {
+ case AllocationCallbackRecord::TYPE_ALLOCATION:
+ {
+ DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.allocation.returnedPtr));
+
+ if (record.data.allocation.returnedPtr)
+ {
+ ptrToSlotIndex[record.data.allocation.returnedPtr] = allocations.size();
+ allocations.push_back(AllocationSlot(record, true));
+ }
+
+ break;
+ }
+
+ case AllocationCallbackRecord::TYPE_REALLOCATION:
+ {
+ if (de::contains(ptrToSlotIndex, record.data.reallocation.original))
+ {
+ const size_t origSlotNdx = ptrToSlotIndex[record.data.reallocation.original];
+ AllocationSlot& origSlot = allocations[origSlotNdx];
+
+ DE_ASSERT(record.data.reallocation.original != DE_NULL);
+
+ if (record.data.reallocation.size > 0)
+ {
+ if (getAlignment(origSlot.record) != record.data.reallocation.alignment)
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_DIFFERENT_ALIGNMENT));
+
+ if (record.data.reallocation.original == record.data.reallocation.returnedPtr)
+ {
+ if (!origSlot.isLive)
+ {
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_FREED_PTR));
+ origSlot.isLive = true; // Mark live to suppress further errors
+ }
+
+ // Just update slot record
+ allocations[origSlotNdx].record = record;
+ }
+ else
+ {
+ DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.reallocation.returnedPtr));
+
+ if (record.data.reallocation.returnedPtr)
+ {
+ allocations[origSlotNdx].isLive = false;
+ ptrToSlotIndex[record.data.reallocation.returnedPtr] = allocations.size();
+ allocations.push_back(AllocationSlot(record, true));
+ }
+ // else original ptr remains valid and live
+ }
+ }
+ else
+ {
+ DE_ASSERT(!record.data.reallocation.returnedPtr);
+
+ origSlot.isLive = false;
+ }
+ }
+ else
+ {
+ if (record.data.reallocation.original)
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_NOT_ALLOCATED_PTR));
+
+ if (record.data.reallocation.returnedPtr)
+ {
+ DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.reallocation.returnedPtr));
+ ptrToSlotIndex[record.data.reallocation.returnedPtr] = allocations.size();
+ allocations.push_back(AllocationSlot(record, true));
+ }
+ }
+
+ break;
+ }
+
+ case AllocationCallbackRecord::TYPE_FREE:
+ {
+ if (record.data.free.mem != DE_NULL) // Freeing null pointer is valid and ignored
+ {
+ if (de::contains(ptrToSlotIndex, record.data.free.mem))
+ {
+ const size_t slotNdx = ptrToSlotIndex[record.data.free.mem];
+
+ if (allocations[slotNdx].isLive)
+ allocations[slotNdx].isLive = false;
+ else
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_DOUBLE_FREE));
+ }
+ else
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_FREE_NOT_ALLOCATED_PTR));
+ }
+
+ break;
+ }
+
+ case AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION:
+ case AllocationCallbackRecord::TYPE_INTERNAL_FREE:
+ {
+ if (de::inBounds(record.data.internalAllocation.type, (VkInternalAllocationType)0, VK_INTERNAL_ALLOCATION_TYPE_LAST))
+ {
+ size_t* const totalAllocSizePtr = &results->internalAllocationTotal[record.data.internalAllocation.type][record.data.internalAllocation.scope];
+ const size_t size = record.data.internalAllocation.size;
+
+ if (record.type == AllocationCallbackRecord::TYPE_FREE)
+ {
+ if (*totalAllocSizePtr < size)
+ {
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL));
+ *totalAllocSizePtr = 0; // Reset to 0 to suppress compound errors
+ }
+ else
+ *totalAllocSizePtr -= size;
+ }
+ else
+ *totalAllocSizePtr += size;
+ }
+ else
+ results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_INTERNAL_ALLOCATION_TYPE));
+
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+ }
+
+ DE_ASSERT(!de::contains(ptrToSlotIndex, DE_NULL));
+
+ // Collect live allocations
+ for (std::vector<AllocationSlot>::const_iterator slotIter = allocations.begin();
+ slotIter != allocations.end();
+ ++slotIter)
+ {
+ if (slotIter->isLive)
+ results->liveAllocations.push_back(slotIter->record);
+ }
+}
+
+bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits)
+{
+ using tcu::TestLog;
+
+ size_t numLeaks = 0;
+
+ if (!results.violations.empty())
+ {
+ for (size_t violationNdx = 0; violationNdx < results.violations.size(); ++violationNdx)
+ {
+ log << TestLog::Message << "VIOLATION " << (violationNdx+1)
+ << ": " << results.violations[violationNdx]
+ << " (" << results.violations[violationNdx].record << ")"
+ << TestLog::EndMessage;
+ }
+
+ log << TestLog::Message << "ERROR: Found " << results.violations.size() << " invalid allocation callbacks!" << TestLog::EndMessage;
+ }
+
+ // Verify live allocations
+ for (size_t liveNdx = 0; liveNdx < results.liveAllocations.size(); ++liveNdx)
+ {
+ const AllocationCallbackRecord& record = results.liveAllocations[liveNdx];
+ const VkSystemAllocationScope scope = record.type == AllocationCallbackRecord::TYPE_ALLOCATION ? record.data.allocation.scope
+ : record.type == AllocationCallbackRecord::TYPE_REALLOCATION ? record.data.reallocation.scope
+ : VK_SYSTEM_ALLOCATION_SCOPE_LAST;
+
+ DE_ASSERT(de::inBounds(scope, (VkSystemAllocationScope)0, VK_SYSTEM_ALLOCATION_SCOPE_LAST));
+
+ if ((allowedLiveAllocScopeBits & (1u << scope)) == 0)
+ {
+ log << TestLog::Message << "LEAK " << (numLeaks+1) << ": " << record << TestLog::EndMessage;
+ numLeaks += 1;
+ }
+ }
+
+ // Verify internal allocations
+ for (int internalAllocTypeNdx = 0; internalAllocTypeNdx < VK_INTERNAL_ALLOCATION_TYPE_LAST; ++internalAllocTypeNdx)
+ {
+ for (int scopeNdx = 0; scopeNdx < VK_SYSTEM_ALLOCATION_SCOPE_LAST; ++scopeNdx)
+ {
+ const VkInternalAllocationType type = (VkInternalAllocationType)internalAllocTypeNdx;
+ const VkSystemAllocationScope scope = (VkSystemAllocationScope)scopeNdx;
+ const size_t totalAllocated = results.internalAllocationTotal[type][scope];
+
+ if ((allowedLiveAllocScopeBits & (1u << scopeNdx)) == 0 &&
+ totalAllocated > 0)
+ {
+ log << TestLog::Message << "LEAK " << (numLeaks+1) << ": " << totalAllocated
+ << " bytes of (" << type << ", " << scope << ") internal memory is still allocated"
+ << TestLog::EndMessage;
+ numLeaks += 1;
+ }
+ }
+ }
+
+ if (numLeaks > 0)
+ log << TestLog::Message << "ERROR: Found " << numLeaks << " memory leaks!" << TestLog::EndMessage;
+
+ return results.violations.empty() && numLeaks == 0;
+}
+
+bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits)
+{
+ AllocationCallbackValidationResults validationResults;
+
+ validateAllocationCallbacks(recorder, &validationResults);
+
+ return checkAndLog(log, validationResults, allowedLiveAllocScopeBits);
+}
+
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record)
+{
+ switch (record.type)
+ {
+ case AllocationCallbackRecord::TYPE_ALLOCATION:
+ str << "ALLOCATION: size=" << record.data.allocation.size
+ << ", alignment=" << record.data.allocation.alignment
+ << ", scope=" << record.data.allocation.scope
+ << ", returnedPtr=" << tcu::toHex(record.data.allocation.returnedPtr);
+ break;
+
+ case AllocationCallbackRecord::TYPE_REALLOCATION:
+ str << "REALLOCATION: original=" << tcu::toHex(record.data.reallocation.original)
+ << ", size=" << record.data.reallocation.size
+ << ", alignment=" << record.data.reallocation.alignment
+ << ", scope=" << record.data.reallocation.scope
+ << ", returnedPtr=" << tcu::toHex(record.data.reallocation.returnedPtr);
+ break;
+
+ case AllocationCallbackRecord::TYPE_FREE:
+ str << "FREE: mem=" << tcu::toHex(record.data.free.mem);
+ break;
+
+ case AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION:
+ case AllocationCallbackRecord::TYPE_INTERNAL_FREE:
+ str << "INTERNAL_" << (record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION ? "ALLOCATION" : "FREE")
+ << ": size=" << record.data.internalAllocation.size
+ << ", type=" << record.data.internalAllocation.type
+ << ", scope=" << record.data.internalAllocation.scope;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ return str;
+}
+
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation)
+{
+ switch (violation.reason)
+ {
+ case AllocationCallbackViolation::REASON_DOUBLE_FREE:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_FREE);
+ str << "Double free of " << tcu::toHex(violation.record.data.free.mem);
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_FREE_NOT_ALLOCATED_PTR:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_FREE);
+ str << "Attempt to free " << tcu::toHex(violation.record.data.free.mem) << " which has not been allocated";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_REALLOC_NOT_ALLOCATED_PTR:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_REALLOCATION);
+ str << "Attempt to reallocate " << tcu::toHex(violation.record.data.reallocation.original) << " which has not been allocated";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_REALLOC_FREED_PTR:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_REALLOCATION);
+ str << "Attempt to reallocate " << tcu::toHex(violation.record.data.reallocation.original) << " which has been freed";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE);
+ str << "Internal allocation total for (" << violation.record.data.internalAllocation.type << ", " << violation.record.data.internalAllocation.scope << ") is negative";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_INVALID_INTERNAL_ALLOCATION_TYPE:
+ {
+ DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION ||
+ violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE);
+ str << "Invalid internal allocation type " << tcu::toHex(violation.record.data.internalAllocation.type);
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_INVALID_ALLOCATION_SCOPE:
+ {
+ str << "Invalid allocation scope";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_INVALID_ALIGNMENT:
+ {
+ str << "Invalid alignment";
+ break;
+ }
+
+ case AllocationCallbackViolation::REASON_REALLOC_DIFFERENT_ALIGNMENT:
+ {
+ str << "Reallocation with different alignment";
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ return str;
+}
+
+} // vk
--- /dev/null
+#ifndef _VKALLOCATIONCALLBACKUTIL_HPP
+#define _VKALLOCATIONCALLBACKUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Memory allocation callback utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "deAppendList.hpp"
+
+#include <vector>
+#include <ostream>
+
+namespace tcu
+{
+class TestLog;
+}
+
+namespace vk
+{
+
+class AllocationCallbacks
+{
+public:
+ AllocationCallbacks (void);
+ virtual ~AllocationCallbacks (void);
+
+ virtual void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
+ virtual void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
+ virtual void free (void* mem) = 0;
+
+ virtual void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
+ virtual void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
+
+ const VkAllocationCallbacks* getCallbacks (void) const { return &m_callbacks; }
+
+private:
+ const VkAllocationCallbacks m_callbacks;
+};
+
+struct AllocationCallbackRecord
+{
+ enum Type
+ {
+ TYPE_ALLOCATION = 0, //! Call to pfnAllocation
+ TYPE_REALLOCATION, //! Call to pfnReallocation
+ TYPE_FREE, //! Call to pfnFree
+ TYPE_INTERNAL_ALLOCATION, //! Call to pfnInternalAllocation
+ TYPE_INTERNAL_FREE, //! Call to pfnInternalFree
+
+ TYPE_LAST
+ };
+
+ Type type;
+
+ union
+ {
+ struct
+ {
+ size_t size;
+ size_t alignment;
+ VkSystemAllocationScope scope;
+ void* returnedPtr;
+ } allocation;
+
+ struct
+ {
+ void* original;
+ size_t size;
+ size_t alignment;
+ VkSystemAllocationScope scope;
+ void* returnedPtr;
+ } reallocation;
+
+ struct
+ {
+ void* mem;
+ } free;
+
+ // \note Used for both INTERNAL_ALLOCATION and INTERNAL_FREE
+ struct
+ {
+ size_t size;
+ VkInternalAllocationType type;
+ VkSystemAllocationScope scope;
+ } internalAllocation;
+ } data;
+
+ AllocationCallbackRecord (void) : type(TYPE_LAST) {}
+
+ static AllocationCallbackRecord allocation (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
+ static AllocationCallbackRecord reallocation (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
+ static AllocationCallbackRecord free (void* mem);
+ static AllocationCallbackRecord internalAllocation (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
+ static AllocationCallbackRecord internalFree (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
+};
+
+class ChainedAllocator : public AllocationCallbacks
+{
+public:
+ ChainedAllocator (const VkAllocationCallbacks* nextAllocator);
+ ~ChainedAllocator (void);
+
+ void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+ void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+ void free (void* mem);
+
+ void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+ void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+
+private:
+ const VkAllocationCallbacks* m_nextAllocator;
+};
+
+class AllocationCallbackRecorder : public ChainedAllocator
+{
+public:
+ AllocationCallbackRecorder (const VkAllocationCallbacks* allocator, deUint32 callCountHint = 1024);
+ ~AllocationCallbackRecorder (void);
+
+ void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+ void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+ void free (void* mem);
+
+ void notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+ void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+
+ typedef de::AppendList<AllocationCallbackRecord>::const_iterator RecordIterator;
+
+ RecordIterator getRecordsBegin (void) const { return m_records.begin(); }
+ RecordIterator getRecordsEnd (void) const { return m_records.end(); }
+
+private:
+ typedef de::AppendList<AllocationCallbackRecord> Records;
+
+ Records m_records;
+};
+
+//! Allocator that starts returning null after N allocs
+class DeterministicFailAllocator : public ChainedAllocator
+{
+public:
+ DeterministicFailAllocator (const VkAllocationCallbacks* allocator, deUint32 numPassingAllocs);
+ ~DeterministicFailAllocator (void);
+
+ void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+ void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+
+private:
+ const deUint32 m_numPassingAllocs;
+ volatile deUint32 m_allocationNdx;
+};
+
+struct AllocationCallbackViolation
+{
+ enum Reason
+ {
+ REASON_DOUBLE_FREE = 0,
+ REASON_FREE_NOT_ALLOCATED_PTR,
+ REASON_REALLOC_NOT_ALLOCATED_PTR,
+ REASON_REALLOC_FREED_PTR,
+ REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL,
+ REASON_INVALID_ALLOCATION_SCOPE,
+ REASON_INVALID_INTERNAL_ALLOCATION_TYPE,
+ REASON_INVALID_ALIGNMENT,
+ REASON_REALLOC_DIFFERENT_ALIGNMENT,
+
+ REASON_LAST
+ };
+
+ AllocationCallbackRecord record;
+ Reason reason;
+
+ AllocationCallbackViolation (void)
+ : reason(REASON_LAST)
+ {}
+
+ AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_)
+ : record(record_)
+ , reason(reason_)
+ {}
+};
+
+struct AllocationCallbackValidationResults
+{
+ std::vector<AllocationCallbackRecord> liveAllocations;
+ size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST];
+ std::vector<AllocationCallbackViolation> violations;
+
+ AllocationCallbackValidationResults (void);
+
+ void clear (void);
+};
+
+void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results);
+bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits);
+bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits);
+
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record);
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation);
+
+const VkAllocationCallbacks* getSystemAllocator (void);
+
+} // vk
+
+#endif // _VKALLOCATIONCALLBACKUTIL_HPP
{
const deUint64 compileStartTime = deGetMicroseconds();
- const int compileRes = shader.parse(&builtinRes, 110, false, EShMsgSpvRules);
+ const int compileRes = shader.parse(&builtinRes, 110, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
glu::ShaderInfo shaderBuildInfo;
shaderBuildInfo.type = (glu::ShaderType)shaderType;
{
const deUint64 linkStartTime = deGetMicroseconds();
- const int linkRes = program.link(EShMsgDefault);
+ const int linkRes = program.link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
buildInfo->program.infoLog = program.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
buildInfo->program.linkOk = (linkRes != 0);
case VK_FILTER_LINEAR:
switch (mipMode)
{
- case VK_SAMPLER_MIPMAP_MODE_BASE: return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
+ case VK_SAMPLER_MIPMAP_MODE_BASE: return tcu::Sampler::LINEAR;
case VK_SAMPLER_MIPMAP_MODE_LINEAR: return tcu::Sampler::LINEAR_MIPMAP_LINEAR;
case VK_SAMPLER_MIPMAP_MODE_NEAREST: return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
default:
case VK_FILTER_NEAREST:
switch (mipMode)
{
- case VK_SAMPLER_MIPMAP_MODE_BASE: return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
+ case VK_SAMPLER_MIPMAP_MODE_BASE: return tcu::Sampler::NEAREST;
case VK_SAMPLER_MIPMAP_MODE_LINEAR: return tcu::Sampler::NEAREST_MIPMAP_LINEAR;
case VK_SAMPLER_MIPMAP_MODE_NEAREST: return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
default:
return swizzle;
}
+//! Get a format the matches the layout in buffer memory used for a
+//! buffer<->image copy on a depth/stencil format.
+tcu::TextureFormat getDepthCopyFormat (VkFormat combinedFormat)
+{
+ switch (combinedFormat)
+ {
+ case VK_FORMAT_D16_UNORM:
+ case VK_FORMAT_X8_D24_UNORM_PACK32:
+ case VK_FORMAT_D32_SFLOAT:
+ return mapVkFormat(combinedFormat);
+
+ case VK_FORMAT_D16_UNORM_S8_UINT:
+ return mapVkFormat(VK_FORMAT_D16_UNORM);
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ return mapVkFormat(VK_FORMAT_X8_D24_UNORM_PACK32);
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ return mapVkFormat(VK_FORMAT_D32_SFLOAT);
+
+ case VK_FORMAT_S8_UINT:
+ default:
+ DE_FATAL("Unexpected depth/stencil format");
+ return tcu::TextureFormat();
+ }
+}
+
+//! Get a format the matches the layout in buffer memory used for a
+//! buffer<->image copy on a depth/stencil format.
+tcu::TextureFormat getStencilCopyFormat (VkFormat combinedFormat)
+{
+ switch (combinedFormat)
+ {
+ case VK_FORMAT_D16_UNORM_S8_UINT:
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ case VK_FORMAT_S8_UINT:
+ return mapVkFormat(VK_FORMAT_S8_UINT);
+
+ case VK_FORMAT_D16_UNORM:
+ case VK_FORMAT_X8_D24_UNORM_PACK32:
+ case VK_FORMAT_D32_SFLOAT:
+ default:
+ DE_FATAL("Unexpected depth/stencil format");
+ return tcu::TextureFormat();
+ }
+}
+
} // vk
tcu::TextureFormat mapVkFormat (VkFormat format);
tcu::CompressedTexFormat mapVkCompressedFormat (VkFormat format);
+tcu::TextureFormat getDepthCopyFormat (VkFormat combinedFormat);
+tcu::TextureFormat getStencilCopyFormat (VkFormat combinedFormat);
tcu::Sampler mapVkSampler (const VkSamplerCreateInfo& samplerCreateInfo);
tcu::Sampler::CompareMode mapVkSamplerCompareOp (VkCompareOp compareOp);
using std::vector;
+// Memory management
+
+template<typename T>
+void* allocateSystemMem (const VkAllocationCallbacks* pAllocator, VkSystemAllocationScope scope)
+{
+ void* ptr = pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(T), sizeof(void*), scope);
+ if (!ptr)
+ throw std::bad_alloc();
+ return ptr;
+}
+
+void freeSystemMem (const VkAllocationCallbacks* pAllocator, void* mem)
+{
+ pAllocator->pfnFree(pAllocator->pUserData, mem);
+}
+
+template<typename Object, typename Handle, typename Parent, typename CreateInfo>
+Handle allocateHandle (Parent parent, const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+ Object* obj = DE_NULL;
+
+ if (pAllocator)
+ {
+ void* mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ try
+ {
+ obj = new (mem) Object(parent, pCreateInfo);
+ DE_ASSERT(obj == mem);
+ }
+ catch (...)
+ {
+ pAllocator->pfnFree(pAllocator->pUserData, mem);
+ throw;
+ }
+ }
+ else
+ obj = new Object(parent, pCreateInfo);
+
+ return reinterpret_cast<Handle>(obj);
+}
+
+template<typename Object, typename Handle, typename CreateInfo>
+Handle allocateHandle (const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+ Object* obj = DE_NULL;
+
+ if (pAllocator)
+ {
+ void* mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ try
+ {
+ obj = new (mem) Object(pCreateInfo);
+ DE_ASSERT(obj == mem);
+ }
+ catch (...)
+ {
+ pAllocator->pfnFree(pAllocator->pUserData, mem);
+ throw;
+ }
+ }
+ else
+ obj = new Object(pCreateInfo);
+
+ return reinterpret_cast<Handle>(obj);
+}
+
+template<typename Object, typename Handle>
+void freeHandle (Handle handle, const VkAllocationCallbacks* pAllocator)
+{
+ Object* obj = reinterpret_cast<Object*>(handle);
+
+ if (pAllocator)
+ {
+ obj->~Object();
+ freeSystemMem(pAllocator, reinterpret_cast<void*>(obj));
+ }
+ else
+ delete obj;
+}
+
+template<typename Object, typename Handle, typename CreateInfo>
+Handle allocateNonDispHandle (VkDevice device, const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+ Object* const obj = allocateHandle<Object, Object*>(device, pCreateInfo, pAllocator);
+ return Handle((deUint64)(deUintptr)obj);
+}
+
+template<typename Object, typename Handle>
+void freeNonDispHandle (Handle handle, const VkAllocationCallbacks* pAllocator)
+{
+ freeHandle<Object>(reinterpret_cast<Object*>((deUintptr)handle.getInternal()), pAllocator);
+}
+
+// Object definitions
+
#define VK_NULL_RETURN(STMT) \
do { \
try { \
m_managedSets.clear();
}
+// API implementation
+
extern "C"
{
return reinterpret_cast<Device*>(device)->getProcAddr(pName);
}
-VKAPI_ATTR VkResult VKAPI_CALL createGraphicsPipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks*, VkPipeline* pPipelines)
+VKAPI_ATTR VkResult VKAPI_CALL createGraphicsPipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines)
{
- for (deUint32 ndx = 0; ndx < count; ndx++)
- pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
- return VK_SUCCESS;
+ deUint32 allocNdx;
+ try
+ {
+ for (allocNdx = 0; allocNdx < count; allocNdx++)
+ pPipelines[allocNdx] = allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos+allocNdx, pAllocator);
+
+ return VK_SUCCESS;
+ }
+ catch (const std::bad_alloc&)
+ {
+ for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+ freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ catch (VkResult err)
+ {
+ for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+ freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+ return err;
+ }
}
-VKAPI_ATTR VkResult VKAPI_CALL createComputePipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks*, VkPipeline* pPipelines)
+VKAPI_ATTR VkResult VKAPI_CALL createComputePipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines)
{
- for (deUint32 ndx = 0; ndx < count; ndx++)
- pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
- return VK_SUCCESS;
+ deUint32 allocNdx;
+ try
+ {
+ for (allocNdx = 0; allocNdx < count; allocNdx++)
+ pPipelines[allocNdx] = allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos+allocNdx, pAllocator);
+
+ return VK_SUCCESS;
+ }
+ catch (const std::bad_alloc&)
+ {
+ for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+ freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ catch (VkResult err)
+ {
+ for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+ freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+ return err;
+ }
}
VKAPI_ATTR VkResult VKAPI_CALL enumeratePhysicalDevices (VkInstance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pDevices)
VKAPI_ATTR VkResult VKAPI_CALL createInstance (const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pInstance = reinterpret_cast<VkInstance>(new Instance(pCreateInfo)));
+ VK_NULL_RETURN((*pInstance = allocateHandle<Instance, VkInstance>(pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createDevice (VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pDevice = reinterpret_cast<VkDevice>(new Device(physicalDevice, pCreateInfo)));
+ VK_NULL_RETURN((*pDevice = allocateHandle<Device, VkDevice>(physicalDevice, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL allocateMemory (VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pMemory = VkDeviceMemory((deUint64)(deUintptr)new DeviceMemory(device, pAllocateInfo)));
+ VK_NULL_RETURN((*pMemory = allocateNonDispHandle<DeviceMemory, VkDeviceMemory>(device, pAllocateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createFence (VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pFence = VkFence((deUint64)(deUintptr)new Fence(device, pCreateInfo)));
+ VK_NULL_RETURN((*pFence = allocateNonDispHandle<Fence, VkFence>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createSemaphore (VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pSemaphore = VkSemaphore((deUint64)(deUintptr)new Semaphore(device, pCreateInfo)));
+ VK_NULL_RETURN((*pSemaphore = allocateNonDispHandle<Semaphore, VkSemaphore>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createEvent (VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pEvent = VkEvent((deUint64)(deUintptr)new Event(device, pCreateInfo)));
+ VK_NULL_RETURN((*pEvent = allocateNonDispHandle<Event, VkEvent>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createQueryPool (VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pQueryPool = VkQueryPool((deUint64)(deUintptr)new QueryPool(device, pCreateInfo)));
+ VK_NULL_RETURN((*pQueryPool = allocateNonDispHandle<QueryPool, VkQueryPool>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createBuffer (VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pBuffer = VkBuffer((deUint64)(deUintptr)new Buffer(device, pCreateInfo)));
+ VK_NULL_RETURN((*pBuffer = allocateNonDispHandle<Buffer, VkBuffer>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createBufferView (VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pView = VkBufferView((deUint64)(deUintptr)new BufferView(device, pCreateInfo)));
+ VK_NULL_RETURN((*pView = allocateNonDispHandle<BufferView, VkBufferView>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createImage (VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pImage = VkImage((deUint64)(deUintptr)new Image(device, pCreateInfo)));
+ VK_NULL_RETURN((*pImage = allocateNonDispHandle<Image, VkImage>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createImageView (VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pView = VkImageView((deUint64)(deUintptr)new ImageView(device, pCreateInfo)));
+ VK_NULL_RETURN((*pView = allocateNonDispHandle<ImageView, VkImageView>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createShaderModule (VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pShaderModule = VkShaderModule((deUint64)(deUintptr)new ShaderModule(device, pCreateInfo)));
+ VK_NULL_RETURN((*pShaderModule = allocateNonDispHandle<ShaderModule, VkShaderModule>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createPipelineCache (VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pPipelineCache = VkPipelineCache((deUint64)(deUintptr)new PipelineCache(device, pCreateInfo)));
+ VK_NULL_RETURN((*pPipelineCache = allocateNonDispHandle<PipelineCache, VkPipelineCache>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createPipelineLayout (VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pPipelineLayout = VkPipelineLayout((deUint64)(deUintptr)new PipelineLayout(device, pCreateInfo)));
+ VK_NULL_RETURN((*pPipelineLayout = allocateNonDispHandle<PipelineLayout, VkPipelineLayout>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createSampler (VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pSampler = VkSampler((deUint64)(deUintptr)new Sampler(device, pCreateInfo)));
+ VK_NULL_RETURN((*pSampler = allocateNonDispHandle<Sampler, VkSampler>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createDescriptorSetLayout (VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pSetLayout = VkDescriptorSetLayout((deUint64)(deUintptr)new DescriptorSetLayout(device, pCreateInfo)));
+ VK_NULL_RETURN((*pSetLayout = allocateNonDispHandle<DescriptorSetLayout, VkDescriptorSetLayout>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createDescriptorPool (VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pDescriptorPool = VkDescriptorPool((deUint64)(deUintptr)new DescriptorPool(device, pCreateInfo)));
+ VK_NULL_RETURN((*pDescriptorPool = allocateNonDispHandle<DescriptorPool, VkDescriptorPool>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createFramebuffer (VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pFramebuffer = VkFramebuffer((deUint64)(deUintptr)new Framebuffer(device, pCreateInfo)));
+ VK_NULL_RETURN((*pFramebuffer = allocateNonDispHandle<Framebuffer, VkFramebuffer>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createRenderPass (VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pRenderPass = VkRenderPass((deUint64)(deUintptr)new RenderPass(device, pCreateInfo)));
+ VK_NULL_RETURN((*pRenderPass = allocateNonDispHandle<RenderPass, VkRenderPass>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createCommandPool (VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool)
{
DE_UNREF(pAllocator);
- VK_NULL_RETURN(*pCommandPool = VkCommandPool((deUint64)(deUintptr)new CommandPool(device, pCreateInfo)));
+ VK_NULL_RETURN((*pCommandPool = allocateNonDispHandle<CommandPool, VkCommandPool>(device, pCreateInfo, pAllocator)));
}
VKAPI_ATTR void VKAPI_CALL destroyInstance (VkInstance instance, const VkAllocationCallbacks* pAllocator)
{
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Instance*>(instance);
+ freeHandle<Instance, VkInstance>(instance, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyDevice (VkDevice device, const VkAllocationCallbacks* pAllocator)
{
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Device*>(device);
+ freeHandle<Device, VkDevice>(device, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL freeMemory (VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<DeviceMemory*>((deUintptr)memory.getInternal());
+ freeNonDispHandle<DeviceMemory, VkDeviceMemory>(memory, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyFence (VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Fence*>((deUintptr)fence.getInternal());
+ freeNonDispHandle<Fence, VkFence>(fence, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroySemaphore (VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Semaphore*>((deUintptr)semaphore.getInternal());
+ freeNonDispHandle<Semaphore, VkSemaphore>(semaphore, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyEvent (VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Event*>((deUintptr)event.getInternal());
+ freeNonDispHandle<Event, VkEvent>(event, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyQueryPool (VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<QueryPool*>((deUintptr)queryPool.getInternal());
+ freeNonDispHandle<QueryPool, VkQueryPool>(queryPool, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyBuffer (VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Buffer*>((deUintptr)buffer.getInternal());
+ freeNonDispHandle<Buffer, VkBuffer>(buffer, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyBufferView (VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<BufferView*>((deUintptr)bufferView.getInternal());
+ freeNonDispHandle<BufferView, VkBufferView>(bufferView, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyImage (VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Image*>((deUintptr)image.getInternal());
+ freeNonDispHandle<Image, VkImage>(image, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyImageView (VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<ImageView*>((deUintptr)imageView.getInternal());
+ freeNonDispHandle<ImageView, VkImageView>(imageView, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyShaderModule (VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<ShaderModule*>((deUintptr)shaderModule.getInternal());
+ freeNonDispHandle<ShaderModule, VkShaderModule>(shaderModule, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyPipelineCache (VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<PipelineCache*>((deUintptr)pipelineCache.getInternal());
+ freeNonDispHandle<PipelineCache, VkPipelineCache>(pipelineCache, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyPipeline (VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Pipeline*>((deUintptr)pipeline.getInternal());
+ freeNonDispHandle<Pipeline, VkPipeline>(pipeline, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyPipelineLayout (VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<PipelineLayout*>((deUintptr)pipelineLayout.getInternal());
+ freeNonDispHandle<PipelineLayout, VkPipelineLayout>(pipelineLayout, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroySampler (VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Sampler*>((deUintptr)sampler.getInternal());
+ freeNonDispHandle<Sampler, VkSampler>(sampler, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyDescriptorSetLayout (VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<DescriptorSetLayout*>((deUintptr)descriptorSetLayout.getInternal());
+ freeNonDispHandle<DescriptorSetLayout, VkDescriptorSetLayout>(descriptorSetLayout, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<DescriptorPool*>((deUintptr)descriptorPool.getInternal());
+ freeNonDispHandle<DescriptorPool, VkDescriptorPool>(descriptorPool, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyFramebuffer (VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<Framebuffer*>((deUintptr)framebuffer.getInternal());
+ freeNonDispHandle<Framebuffer, VkFramebuffer>(framebuffer, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyRenderPass (VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<RenderPass*>((deUintptr)renderPass.getInternal());
+ freeNonDispHandle<RenderPass, VkRenderPass>(renderPass, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL destroyCommandPool (VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator)
{
DE_UNREF(device);
- DE_UNREF(pAllocator);
- delete reinterpret_cast<CommandPool*>((deUintptr)commandPool.getInternal());
+ freeNonDispHandle<CommandPool, VkCommandPool>(commandPool, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceFeatures (VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures)
*//*--------------------------------------------------------------------*/
#include "vkDefs.hpp"
+#include "deMemory.h"
#include <vector>
bool isShaderStageSupported (const VkPhysicalDeviceFeatures& deviceFeatures, VkShaderStageFlagBits stage);
+template <typename Context, typename Interface, typename Type>
+bool validateInitComplete(Context context, void (Interface::*Function)(Context, Type*)const, const Interface& interface)
+{
+ Type vec[2];
+ deMemset(&vec[0], 0x00, sizeof(Type));
+ deMemset(&vec[1], 0xFF, sizeof(Type));
+
+ (interface.*Function)(context, &vec[0]);
+ (interface.*Function)(context, &vec[1]);
+
+ for (size_t ndx = 0; ndx < sizeof(Type); ndx++)
+ {
+ if (reinterpret_cast<deUint8*>(&vec[0])[ndx] != reinterpret_cast<deUint8*>(&vec[1])[ndx])
+ return false;
+ }
+
+ return true;
+}
+
} // vk
#endif // _VKQUERYUTIL_HPP
for function in createFuncs:
objectType = function.arguments[-1].type.replace("*", "").strip()
- argsStr = ", ".join([a.name for a in function.arguments[:-2]])
+ argsStr = ", ".join([a.name for a in function.arguments[:-1]])
yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
yield "{"
yield "\tDE_UNREF(%s);" % function.arguments[-2].name
if getHandle(objectType).type == Handle.TYPE_NONDISP:
- yield "\tVK_NULL_RETURN(*%s = %s((deUint64)(deUintptr)new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+ yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
else:
- yield "\tVK_NULL_RETURN(*%s = reinterpret_cast<%s>(new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+ yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
yield "}"
yield ""
yield "{"
for arg in function.arguments[:-2]:
yield "\tDE_UNREF(%s);" % arg.name
- yield "\tDE_UNREF(%s);" % function.arguments[-1].name
if getHandle(objectArg.type).type == Handle.TYPE_NONDISP:
- yield "\tdelete reinterpret_cast<%s*>((deUintptr)%s.getInternal());" % (objectArg.type[2:], objectArg.name)
+ yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
else:
- yield "\tdelete reinterpret_cast<%s*>(%s);" % (objectArg.type[2:], objectArg.name)
+ yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
yield "}"
yield ""
vktTestCaseUtil.hpp
vktTestPackage.cpp
vktTestPackage.hpp
- vktInfo.cpp
- vktInfo.hpp
vktShaderLibrary.cpp
vktShaderLibrary.hpp
vktRenderPassTests.cpp
vktApiBufferViewCreateTests.hpp
vktApiBufferViewAccessTests.cpp
vktApiBufferViewAccessTests.hpp
+ vktApiFeatureInfo.cpp
+ vktApiFeatureInfo.hpp
)
set(DEQP_VK_API_LIBS
{
const VkDeviceSize testSizes[] =
{
- 0,
+ 1,
1181,
15991,
16384
deUint32 bufferSize;
deUint32 bufferViewSize;
deUint32 elementOffset;
- deUint32 offset;
};
class BufferViewTestInstance : public vkt::TestInstance
Move<VkFence> m_fence;
};
-static void generateBuffer (std::vector<tcu::IVec4>& uniformData, deUint32 bufferSize, deInt8 factor = 1)
+static void generateBuffer (std::vector<deUint32>& uniformData, deUint32 bufferSize, deInt8 factor = 1)
{
for (deUint32 i = 0; i < bufferSize; ++i)
- uniformData.push_back(tcu::IVec4(factor * i, factor * (i + 1), factor * (i + 2), factor * (i + 3)));
+ uniformData.push_back(factor * i);
}
void BufferViewTestInstance::createQuad (void)
{
{
0u, // deUint32 binding;
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType;
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, // VkDescriptorType descriptorType;
1u, // deUint32 arraySize;
VK_SHADER_STAGE_ALL, // VkShaderStageFlags stageFlags;
DE_NULL // const VkSampler* pImmutableSamplers;
m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams);
// Generate buffer
- std::vector<tcu::IVec4> uniformData;
+ std::vector<deUint32> uniformData;
generateBuffer(uniformData, testCase.bufferSize);
- const VkDeviceSize uniformSize = testCase.bufferSize * sizeof(tcu::Vec4);
+ const VkDeviceSize uniformSize = testCase.bufferSize * sizeof(deUint32);
const VkBufferCreateInfo uniformBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
(VkBufferViewCreateFlags)0,
*m_uniformBuffer, // VkBuffer buffer;
m_colorFormat, // VkFormat format;
- m_testCase.elementOffset * sizeof(tcu::IVec4) + m_testCase.offset, // VkDeviceSize offset;
- m_testCase.bufferViewSize * sizeof(tcu::IVec4) // VkDeviceSize range;
+ m_testCase.elementOffset * sizeof(deUint32), // VkDeviceSize offset;
+ m_testCase.bufferViewSize * sizeof(deUint32) // VkDeviceSize range;
};
m_uniformBufferView = createBufferView(vk, vkDevice, &viewInfo);
const VkDescriptorPoolSize descriptorTypes[1] =
{
{
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType type;
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, // VkDescriptorType type;
1 // deUint32 count;
}
};
1.0f, // float lineWidth;
};
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ VK_FALSE, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable;
+ VK_FALSE // VkBool32 alphaToOneEnable;
+ };
+
const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
false, // VkBool32 blendEnable;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
- DE_NULL, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
&dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
for (deInt32 i = 0; i < (deInt32) m_renderSize.x(); ++i)
{
tcu::IVec4 pixel = pixelBuffer.getPixelInt(i, i);
- deInt32 expected = factor * (m_testCase.elementOffset + i + (m_testCase.offset / 4) % 4);
+ deInt32 expected = factor * (m_testCase.elementOffset + i);
deInt32 actual = pixel[0];
if (expected != actual)
{
}
// Generate and bind another buffer
- std::vector<tcu::IVec4> uniformData;
- const VkDeviceSize uniformSize = m_testCase.bufferSize * sizeof(tcu::Vec4);
+ std::vector<deUint32> uniformData;
+ const VkDeviceSize uniformSize = m_testCase.bufferSize * sizeof(deUint32);
const deInt8 factor = 2;
generateBuffer(uniformData, m_testCase.bufferSize, factor);
programCollection.glslSources.add("frag") << glu::FragmentSource(
"#version 310 es\n"
- "layout (set=0, binding=0) uniform u_buffer {\n"
- " highp uint item[" + de::toString(m_bufferViewTestInfo.bufferViewSize) + "];\n"
- "};\n"
+ "#extension GL_EXT_texture_buffer : enable\n"
+ "layout (set=0, binding=0) uniform highp usamplerBuffer u_buffer;\n"
"layout (location = 0) out highp uint o_color;\n"
"void main()\n"
"{\n"
- " o_color = item[int(gl_FragCoord.x)];\n"
+ " o_color = texelFetch(u_buffer, int(gl_FragCoord.x)).x;\n"
"}\n");
}
512, // deUint32 bufferSize
512, // deUint32 bufferViewSize
0, // deUint32 elementOffset
- 0, // deUint32 offset
};
std::ostringstream description;
- description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+ description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_complete", description.str(), info));
}
4096, // deUint32 bufferSize
512, // deUint32 bufferViewSize
0, // deUint32 elementOffset
- 0, // deUint32 offset
};
std::ostringstream description;
- description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+ description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset0", description.str(), info));
}
4096, // deUint32 bufferSize
512, // deUint32 bufferViewSize
128, // deUint32 elementOffset
- 0, // deUint32 offset
};
std::ostringstream description;
- description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+ description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset1", description.str(), info));
}
- {
- BufferViewCaseParams info =
- {
- 4096, // deUint32 bufferSize
- 512, // deUint32 bufferViewSize
- 128, // deUint32 elementOffset
- 4, // deUint32 offset
- };
- std::ostringstream description;
- description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
- bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset2", description.str(), info));
- }
-
return bufferViewTests.release();
}
struct BufferViewCaseParameters
{
- VkFormat format;
- VkDeviceSize offset;
- VkDeviceSize range;
- VkBufferUsageFlags usage;
- bool beforeAllocateMemory;
+ VkFormat format;
+ VkDeviceSize offset;
+ VkDeviceSize range;
+ VkBufferUsageFlags usage;
+ VkFormatFeatureFlags features;
+ bool beforeAllocateMemory;
};
class BufferViewTestInstance : public TestInstance
{
public:
BufferViewTestInstance (Context& ctx,
- BufferViewCaseParameters createInfo)
- : TestInstance (ctx)
- , m_testCase (createInfo)
- {}
+ BufferViewCaseParameters createInfo);
virtual tcu::TestStatus iterate (void);
private:
BufferViewCaseParameters m_testCase;
};
+BufferViewTestInstance::BufferViewTestInstance (Context& ctx,
+ BufferViewCaseParameters createInfo)
+ : TestInstance (ctx)
+ , m_testCase (createInfo)
+{
+ if (m_context.getDeviceFeatures().sparseBinding == 0 && m_testCase.beforeAllocateMemory == false)
+ throw tcu::NotSupportedError("The test is not supported - it needs missing 'sparseBinding' feature of Vulkan");
+}
+
tcu::TestStatus BufferViewTestInstance::iterate (void)
{
// Create buffer
VkFormatProperties properties;
const VkBufferCreateInfo bufferParams =
{
- VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
- DE_NULL, // const void* pNext;
- VK_BUFFER_CREATE_SPARSE_BINDING_BIT, // VkBufferCreateFlags flags;
- size, // VkDeviceSize size;
- m_testCase.usage, // VkBufferUsageFlags usage;
- VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
- 1u, // deUint32 queueFamilyCount;
- &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkBufferCreateFlags)(m_testCase.beforeAllocateMemory == true
+ ? 0
+ : VK_BUFFER_CREATE_SPARSE_BINDING_BIT), // VkBufferCreateFlags flags;
+ size, // VkDeviceSize size;
+ m_testCase.usage, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_context.getInstanceInterface().getPhysicalDeviceFormatProperties(m_context.getPhysicalDevice(), m_testCase.format, &properties);
- if (!(properties.bufferFeatures & m_testCase.usage))
+ if (!(properties.bufferFeatures & m_testCase.features))
TCU_THROW(NotSupportedError, "Format not supported");
if (vk.createBuffer(vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL, &testBuffer) != VK_SUCCESS)
0, // VkDeviceSize offset;
range, // VkDeviceSize range;
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
false // beforeAlloceMemory bool;
};
bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_before_uniform", testDescription.str(), testParams));
0, // VkDeviceSize offset;
range, // VkDeviceSize range;
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
true // beforeAlloceMemory bool;
};
bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_after_uniform", testDescription.str(), testParams));
0, // VkDeviceSize offset;
range, // VkDeviceSize range;
VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
false // beforeAlloceMemory bool;
};
bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_before_storage", testDescription.str(), testParams));
0, // VkDeviceSize offset;
range, // VkDeviceSize range;
VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
true // beforeAlloceMemory bool;
};
bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_after_storage", testDescription.str(), testParams));
}
}
+deUint32 getGlobalMaxQueueCount(const vector<VkQueueFamilyProperties>& queueFamilyProperties)
+{
+ deUint32 maxQueueCount = 0;
+
+ for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < (deUint32)queueFamilyProperties.size(); queueFamilyNdx++)
+ {
+ maxQueueCount = de::max(maxQueueCount, queueFamilyProperties[queueFamilyNdx].queueCount);
+ }
+
+ return maxQueueCount;
+}
+
tcu::TestStatus createDeviceWithVariousQueueCountsTest (Context& context)
{
tcu::TestLog& log = context.getTestContext().getLog();
const InstanceDriver instanceDriver (platformInterface, instance.get());
const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
const vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
+ const vector<float> queuePriorities (getGlobalMaxQueueCount(queueFamilyProperties), 1.0f);
vector<VkDeviceQueueCreateInfo> deviceQueueCreateInfos;
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < (deUint32)queueFamilyProperties.size(); queueFamilyNdx++)
(VkDeviceQueueCreateFlags)0u,
queueFamilyNdx,
queueCount,
- DE_NULL
+ queuePriorities.data()
};
deviceQueueCreateInfos.push_back(queueCreateInfo);
--- /dev/null
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Api Feature Query tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiFeatureInfo.hpp"
+
+#include "vktTestCaseUtil.hpp"
+
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deMemory.h"
+
+namespace vkt
+{
+namespace api
+{
+namespace
+{
+
+using namespace vk;
+using std::vector;
+using std::string;
+using tcu::TestLog;
+using tcu::ScopedLogSection;
+
+enum
+{
+ GUARD_SIZE = 0x20, //!< Number of bytes to check
+ GUARD_VALUE = 0xcd, //!< Data pattern
+};
+
+enum LimitFormat
+{
+ LIMIT_FORMAT_SIGNED_INT,
+ LIMIT_FORMAT_UNSIGNED_INT,
+ LIMIT_FORMAT_FLOAT,
+ LIMIT_FORMAT_DEVICE_SIZE,
+
+ LIMIT_FORMAT_LAST
+};
+
+enum LimitType
+{
+ LIMIT_TYPE_MIN,
+ LIMIT_TYPE_MAX,
+
+ LIMIT_TYPE_LAST
+};
+
+#define FEATURE(_X_) DE_OFFSET_OF(VkPhysicalDeviceLimits, _X_),(char*)(#_X_)
+bool validateFeatureLimits(VkPhysicalDeviceProperties* properties, TestLog& log)
+{
+ bool limitsOk = true;
+ VkPhysicalDeviceLimits* limits = &properties->limits;
+ struct FeatureLimitTable
+ {
+ deUint32 offset;
+ char* name;
+ deUint32 uintVal; //!< Format is UNSIGNED_INT
+ deInt32 intVal; //!< Format is SIGNED_INT
+ deUint64 deviceSizeVal; //!< Format is DEVICE_SIZE
+ float floatVal; //!< Format is FLOAT
+ LimitFormat format;
+ LimitType type;
+ } featureLimitTable[] = //!< From gitlab.khronos.org/vulkan/vulkan.git:doc/specs/vulkan/chapters/features.txt@40de2de5b8167ec277ea2969d621857094323831
+ {
+ { FEATURE(maxImageDimension1D), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxImageDimension2D), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxImageDimension3D), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxImageDimensionCube), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxImageArrayLayers), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTexelBufferElements), 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxUniformBufferRange), 16384, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPushConstantsSize), 128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxMemoryAllocationCount), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(bufferImageGranularity), 0, 0, 131072, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MAX },
+ { FEATURE(sparseAddressSpaceSize), 0, 0, 2UL*1024*1024*1024, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MIN },
+ { FEATURE(maxBoundDescriptorSets), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorSamplers), 16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorUniformBuffers), 12, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorStorageBuffers), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorSampledImages), 16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorStorageImages), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxPerStageDescriptorInputAttachments), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetSamplers), 96, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetUniformBuffers), 72, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetUniformBuffersDynamic), 8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetStorageBuffers), 24, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetStorageBuffersDynamic), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetSampledImages), 96, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDescriptorSetStorageImages), 24, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxVertexInputAttributes), 16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxVertexInputBindings), 16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxVertexInputAttributeOffset), 2047, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxVertexInputBindingStride), 2048, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxVertexOutputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationGenerationLevel), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationPatchSize), 32, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationControlPerVertexInputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationControlPerVertexOutputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationControlPerPatchOutputComponents), 120, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationControlTotalOutputComponents), 2048, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationEvaluationInputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxTessellationEvaluationOutputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxGeometryShaderInvocations), 32, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxGeometryInputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxGeometryOutputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxGeometryOutputVertices), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxGeometryTotalOutputComponents), 1024, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFragmentInputComponents), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFragmentOutputAttachments), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFragmentDualSrcAttachments), 1, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFragmentCombinedOutputResources), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeSharedMemorySize), 16384, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupCount[0]), 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupCount[1]), 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupCount[2]), 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupInvocations), 128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupSize[0]), 128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupSize[1]), 128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxComputeWorkGroupSize[2]), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(subPixelPrecisionBits), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(subTexelPrecisionBits), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(mipmapPrecisionBits), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxDrawIndirectCount), 65535, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxSamplerLodBias), 0, 0, 0, 2.0f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(maxSamplerAnisotropy), 0, 0, 0, 16.0f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(maxViewports), 16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxViewportDimensions[0]), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxViewportDimensions[1]), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(viewportBoundsRange[0]), 0, 0, 0, -8192, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(viewportBoundsRange[1]), 0, 0, 0, 8191, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(viewportSubPixelBits), 0, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(minMemoryMapAlignment), 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(minTexelBufferOffsetAlignment), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+ { FEATURE(minUniformBufferOffsetAlignment), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+ { FEATURE(minStorageBufferOffsetAlignment), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+ { FEATURE(minTexelOffset), 0, -8, 0, 0, LIMIT_FORMAT_SIGNED_INT, LIMIT_TYPE_MAX },
+ { FEATURE(maxTexelOffset), 7, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(minTexelGatherOffset), 0, -8, 0, 0, LIMIT_FORMAT_SIGNED_INT, LIMIT_TYPE_MAX },
+ { FEATURE(maxTexelGatherOffset), 7, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(minInterpolationOffset), 0, 0, 0, -0.5f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(maxInterpolationOffset), 0, 0, 0, 0.5f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(subPixelInterpolationOffsetBits), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFramebufferWidth), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFramebufferHeight), 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxFramebufferLayers), 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxColorAttachments), 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxSampleMaskWords), 1, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxClipDistances), 8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxCullDistances), 8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(maxCombinedClipAndCullDistances), 8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+ { FEATURE(pointSizeRange[0]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(pointSizeRange[1]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(pointSizeRange[0]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(pointSizeRange[1]), 0, 0, 0, 64.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(lineWidthRange[0]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(lineWidthRange[1]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(lineWidthRange[0]), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(lineWidthRange[1]), 0, 0, 0, 8.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+ { FEATURE(pointSizeGranularity), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(lineWidthGranularity), 0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+ { FEATURE(nonCoherentAtomSize), 0, 0, 128, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MAX },
+ };
+
+ log << TestLog::Message << *limits << TestLog::EndMessage;
+
+ for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(featureLimitTable); ndx++)
+ {
+ switch (featureLimitTable[ndx].format)
+ {
+ case LIMIT_FORMAT_UNSIGNED_INT:
+ if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+ {
+ if (*((deUint32*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].uintVal)
+ {
+ log << TestLog::Message << "limit Validation failed " << featureLimitTable[ndx].name
+ << " not valid-limit type MIN - actual is "
+ << *((deUint32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ else
+ {
+ if (*((deUint32*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].uintVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MAX - actual is "
+ << *((deUint32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ break;
+
+ case LIMIT_FORMAT_FLOAT:
+ if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+ {
+ if (*((float*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].floatVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MIN - actual is "
+ << *((float*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ else
+ {
+ if (*((float*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].floatVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MAX actual is "
+ << *((float*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ break;
+
+ case LIMIT_FORMAT_SIGNED_INT:
+ if (featureLimitTable[ndx].type == LIMIT_TYPE_MIN)
+ {
+ if (*((deInt32*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].intVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MIN actual is "
+ << *((deInt32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ else
+ {
+ if (*((deInt32*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].intVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MAX actual is "
+ << *((deInt32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ break;
+
+ case LIMIT_FORMAT_DEVICE_SIZE:
+ if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+ {
+ if (*((deUint64*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].deviceSizeVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MIN actual is "
+ << *((deUint64*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ else
+ {
+ if (*((deUint64*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].deviceSizeVal)
+ {
+ log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+ << " not valid-limit type MAX actual is "
+ << *((deUint64*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+ limitsOk = false;
+ }
+ }
+ break;
+
+ default:
+ DE_ASSERT(0);
+ limitsOk = false;
+ }
+ }
+
+ return limitsOk;
+}
+
+tcu::TestStatus enumeratePhysicalDevices (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ const vector<VkPhysicalDevice> devices = enumeratePhysicalDevices(context.getInstanceInterface(), context.getInstance());
+
+ log << TestLog::Integer("NumDevices", "Number of devices", "", QP_KEY_TAG_NONE, deInt64(devices.size()));
+
+ for (size_t ndx = 0; ndx < devices.size(); ndx++)
+ log << TestLog::Message << ndx << ": " << devices[ndx] << TestLog::EndMessage;
+
+ return tcu::TestStatus::pass("Enumerating devices succeeded");
+}
+
+tcu::TestStatus enumerateInstanceLayers (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ const vector<VkLayerProperties> properties = enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+ for (size_t ndx = 0; ndx < properties.size(); ndx++)
+ log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+ return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateInstanceExtensions (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+
+ {
+ const ScopedLogSection section (log, "Global", "Global Extensions");
+ const vector<VkExtensionProperties> properties = enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL);
+
+ for (size_t ndx = 0; ndx < properties.size(); ndx++)
+ log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+ }
+
+ {
+ const vector<VkLayerProperties> layers = enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+ for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+ {
+ const ScopedLogSection section (log, layer->layerName, string("Layer: ") + layer->layerName);
+ const vector<VkExtensionProperties> properties = enumerateInstanceExtensionProperties(context.getPlatformInterface(), layer->layerName);
+
+ for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+ log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+ }
+ }
+
+ return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus enumerateDeviceLayers (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ const vector<VkLayerProperties> properties = vk::enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+ for (size_t ndx = 0; ndx < properties.size(); ndx++)
+ log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+ return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateDeviceExtensions (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+
+ {
+ const ScopedLogSection section (log, "Global", "Global Extensions");
+ const vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), DE_NULL);
+
+ for (size_t ndx = 0; ndx < properties.size(); ndx++)
+ log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+ }
+
+ {
+ const vector<VkLayerProperties> layers = enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+ for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+ {
+ const ScopedLogSection section (log, layer->layerName, string("Layer: ") + layer->layerName);
+ const vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), layer->layerName);
+
+ for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+ log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+ }
+ }
+
+ return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus deviceFeatures (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ VkPhysicalDeviceFeatures* features;
+ deUint8 buffer[sizeof(VkPhysicalDeviceFeatures) + GUARD_SIZE];
+
+ deMemset(buffer, GUARD_VALUE, sizeof(buffer));
+ features = reinterpret_cast<VkPhysicalDeviceFeatures*>(buffer);
+
+ context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), features);
+
+ log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+ << TestLog::Message << *features << TestLog::EndMessage;
+
+ for (int ndx = 0; ndx < GUARD_SIZE; ndx++)
+ {
+ if (buffer[ndx + sizeof(VkPhysicalDeviceFeatures)] != GUARD_VALUE)
+ {
+ log << TestLog::Message << "deviceFeatures - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("deviceFeatures buffer overflow");
+ }
+ }
+
+ if (!validateInitComplete(context.getPhysicalDevice(), &InstanceInterface::getPhysicalDeviceFeatures, context.getInstanceInterface()))
+ {
+ log << TestLog::Message << "deviceFeatures - VkPhysicalDeviceFeatures not completely initialized" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("deviceFeatures incomplete initialization");
+ }
+
+ return tcu::TestStatus::pass("Query succeeded");
+}
+
+tcu::TestStatus deviceProperties (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ VkPhysicalDeviceProperties* props;
+ deUint8 buffer[sizeof(VkPhysicalDeviceProperties) + GUARD_SIZE];
+
+ props = reinterpret_cast<VkPhysicalDeviceProperties*>(buffer);
+ deMemset(props, GUARD_VALUE, sizeof(buffer));
+
+ context.getInstanceInterface().getPhysicalDeviceProperties(context.getPhysicalDevice(), props);
+
+ log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+ << TestLog::Message << *props << TestLog::EndMessage;
+
+ if (!validateFeatureLimits(props, log))
+ return tcu::TestStatus::fail("deviceProperties - feature limits failed");
+
+ for (int ndx = 0; ndx < GUARD_SIZE; ndx++)
+ {
+ if (buffer[ndx + sizeof(VkPhysicalDeviceProperties)] != GUARD_VALUE)
+ {
+ log << TestLog::Message << "deviceProperties - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("deviceProperties buffer overflow");
+ }
+ }
+
+ if (!validateInitComplete(context.getPhysicalDevice(), &InstanceInterface::getPhysicalDeviceProperties, context.getInstanceInterface()))
+ {
+ log << TestLog::Message << "deviceProperties - VkPhysicalDeviceProperties not completely initialized" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("deviceProperties incomplete initialization");
+ }
+
+ return tcu::TestStatus::pass("DeviceProperites query succeeded");
+}
+
+tcu::TestStatus deviceQueueFamilyProperties (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ const vector<VkQueueFamilyProperties> queueProperties = getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+ log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
+
+ for (size_t queueNdx = 0; queueNdx < queueProperties.size(); queueNdx++)
+ log << TestLog::Message << queueNdx << ": " << queueProperties[queueNdx] << TestLog::EndMessage;
+
+ return tcu::TestStatus::pass("Querying queue properties succeeded");
+}
+
+tcu::TestStatus deviceMemoryProperties (Context& context)
+{
+ TestLog& log = context.getTestContext().getLog();
+ VkPhysicalDeviceMemoryProperties* memProps;
+ deUint8 buffer[sizeof(VkPhysicalDeviceMemoryProperties) + GUARD_SIZE];
+
+ memProps = reinterpret_cast<VkPhysicalDeviceMemoryProperties*>(buffer);
+ deMemset(buffer, GUARD_VALUE, sizeof(buffer));
+
+ context.getInstanceInterface().getPhysicalDeviceMemoryProperties(context.getPhysicalDevice(), memProps);
+
+ log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+ << TestLog::Message << *memProps << TestLog::EndMessage;
+
+ for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
+ {
+ if (buffer[ndx + sizeof(VkPhysicalDeviceMemoryProperties)] != GUARD_VALUE)
+ {
+ log << TestLog::Message << "deviceMemoryProperties - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("deviceMemoryProperties buffer overflow");
+ }
+ }
+
+ return tcu::TestStatus::pass("Querying memory properties succeeded");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createFeatureInfoTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> infoTests (new tcu::TestCaseGroup(testCtx, "info", "Platform Information Tests"));
+
+ {
+ de::MovePtr<tcu::TestCaseGroup> instanceInfoTests (new tcu::TestCaseGroup(testCtx, "instance", "Instance Information Tests"));
+
+ addFunctionCase(instanceInfoTests.get(), "physical_devices", "Physical devices", enumeratePhysicalDevices);
+ addFunctionCase(instanceInfoTests.get(), "layers", "Layers", enumerateInstanceLayers);
+ addFunctionCase(instanceInfoTests.get(), "extensions", "Extensions", enumerateInstanceExtensions);
+
+ infoTests->addChild(instanceInfoTests.release());
+ }
+
+ {
+ de::MovePtr<tcu::TestCaseGroup> deviceInfoTests (new tcu::TestCaseGroup(testCtx, "device", "Device Information Tests"));
+
+ addFunctionCase(deviceInfoTests.get(), "features", "Device Features", deviceFeatures);
+ addFunctionCase(deviceInfoTests.get(), "properties", "Device Properties", deviceProperties);
+ addFunctionCase(deviceInfoTests.get(), "queue_family_properties", "Queue family properties", deviceQueueFamilyProperties);
+ addFunctionCase(deviceInfoTests.get(), "memory_properties", "Memory properties", deviceMemoryProperties);
+ addFunctionCase(deviceInfoTests.get(), "layers", "Layers", enumerateDeviceLayers);
+ addFunctionCase(deviceInfoTests.get(), "extensions", "Extensions", enumerateDeviceExtensions);
+
+ infoTests->addChild(deviceInfoTests.release());
+ }
+
+ return infoTests.release();
+}
+
+} // api
+} // vkt
-#ifndef _VKTINFO_HPP
-#define _VKTINFO_HPP
+#ifndef _VKTAPIFEATUREINFO_HPP
+#define _VKTAPIFEATUREINFO_HPP
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
*//*!
* \file
- * \brief Platform information tests
+ * \brief API Feature Query tests
*//*--------------------------------------------------------------------*/
#include "tcuDefs.hpp"
namespace vkt
{
+namespace api
+{
-tcu::TestCaseGroup* createInfoTests (tcu::TestContext& testCtx);
+tcu::TestCaseGroup* createFeatureInfoTests (tcu::TestContext& testCtx);
+} // api
} // vkt
-#endif // _VKTINFO_HPP
+#endif // _VKTAPIFEATUREINFO_HPP
#include "vkTypeUtil.hpp"
#include "vkPlatform.hpp"
#include "vkStrUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
#include "tcuVector.hpp"
#include "tcuResultCollector.hpp"
struct Environment
{
- const PlatformInterface& vkp;
- const DeviceInterface& vkd;
- VkDevice device;
- deUint32 queueFamilyIndex;
- const BinaryCollection& programBinaries;
- deUint32 maxResourceConsumers; // Maximum number of objects using same Object::Resources concurrently
+ const PlatformInterface& vkp;
+ const DeviceInterface& vkd;
+ VkDevice device;
+ deUint32 queueFamilyIndex;
+ const BinaryCollection& programBinaries;
+ const VkAllocationCallbacks* allocationCallbacks;
+ deUint32 maxResourceConsumers; // Maximum number of objects using same Object::Resources concurrently
Environment (Context& context, deUint32 maxResourceConsumers_)
: vkp (context.getPlatformInterface())
, device (context.getDevice())
, queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, programBinaries (context.getBinaryCollection())
+ , allocationCallbacks (DE_NULL)
, maxResourceConsumers (maxResourceConsumers_)
{
}
- Environment (const PlatformInterface& vkp_,
- const DeviceInterface& vkd_,
- VkDevice device_,
- deUint32 queueFamilyIndex_,
- const BinaryCollection& programBinaries_,
- deUint32 maxResourceConsumers_)
+ Environment (const PlatformInterface& vkp_,
+ const DeviceInterface& vkd_,
+ VkDevice device_,
+ deUint32 queueFamilyIndex_,
+ const BinaryCollection& programBinaries_,
+ const VkAllocationCallbacks* allocationCallbacks_,
+ deUint32 maxResourceConsumers_)
: vkp (vkp_)
, vkd (vkd_)
, device (device_)
, queueFamilyIndex (queueFamilyIndex_)
, programBinaries (programBinaries_)
+ , allocationCallbacks (allocationCallbacks_)
, maxResourceConsumers (maxResourceConsumers_)
{
}
DE_NULL, // ppEnabledExtensionNames
};
- return createInstance(env.vkp, &instanceInfo);
+ return createInstance(env.vkp, &instanceInfo, env.allocationCallbacks);
}
};
}
};
- static Move<VkDevice> create (const Environment&, const Resources& res, const Parameters&)
+ static Move<VkDevice> create (const Environment& env, const Resources& res, const Parameters&)
{
const float queuePriority = 1.0;
DE_NULL, // pEnabledFeatures
};
- return createDevice(res.vki, res.physicalDevice, &deviceInfo);
+ return createDevice(res.vki, res.physicalDevice, &deviceInfo, env.allocationCallbacks);
}
};
params.memoryTypeIndex
};
- return allocateMemory(env.vkd, env.device, &allocInfo);
+ return allocateMemory(env.vkd, env.device, &allocInfo, env.allocationCallbacks);
}
};
&env.queueFamilyIndex
};
- return createBuffer(env.vkd, env.device, &bufferInfo);
+ return createBuffer(env.vkd, env.device, &bufferInfo, env.allocationCallbacks);
}
};
params.range
};
- return createBufferView(env.vkd, env.device, &bufferViewInfo);
+ return createBufferView(env.vkd, env.device, &bufferViewInfo, env.allocationCallbacks);
}
};
params.initialLayout
};
- return createImage(env.vkd, env.device, &imageInfo);
+ return createImage(env.vkd, env.device, &imageInfo, env.allocationCallbacks);
}
};
params.subresourceRange,
};
- return createImageView(env.vkd, env.device, &imageViewInfo);
+ return createImageView(env.vkd, env.device, &imageViewInfo, env.allocationCallbacks);
}
};
params.flags
};
- return createSemaphore(env.vkd, env.device, &semaphoreInfo);
+ return createSemaphore(env.vkd, env.device, &semaphoreInfo, env.allocationCallbacks);
}
};
params.flags
};
- return createFence(env.vkd, env.device, &fenceInfo);
+ return createFence(env.vkd, env.device, &fenceInfo, env.allocationCallbacks);
}
};
params.flags
};
- return createEvent(env.vkd, env.device, &eventInfo);
+ return createEvent(env.vkd, env.device, &eventInfo, env.allocationCallbacks);
}
};
params.pipelineStatistics
};
- return createQueryPool(env.vkd, env.device, &queryPoolInfo);
+ return createQueryPool(env.vkd, env.device, &queryPoolInfo, env.allocationCallbacks);
}
};
(const deUint32*)res.binary.getBinary(),
};
- return createShaderModule(env.vkd, env.device, &shaderModuleInfo);
+ return createShaderModule(env.vkd, env.device, &shaderModuleInfo, env.allocationCallbacks);
}
};
DE_NULL, // pInitialData
};
- return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo);
+ return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo, env.allocationCallbacks);
}
};
params.unnormalizedCoordinates
};
- return createSampler(env.vkd, env.device, &samplerInfo);
+ return createSampler(env.vkd, env.device, &samplerInfo, env.allocationCallbacks);
}
};
(res.bindings.empty() ? DE_NULL : &res.bindings[0])
};
- return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo);
+ return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo, env.allocationCallbacks);
}
};
(params.pushConstantRanges.empty() ? DE_NULL : ¶ms.pushConstantRanges[0]),
};
- return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo);
+ return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo, env.allocationCallbacks);
}
};
DE_NULL // pDependencies
};
- return createRenderPass(env.vkd, env.device, &renderPassInfo);
+ return createRenderPass(env.vkd, env.device, &renderPassInfo, env.allocationCallbacks);
}
};
0, // basePipelineIndex
};
- return createGraphicsPipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+ return createGraphicsPipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo, env.allocationCallbacks);
}
};
0u, // basePipelineIndex
};
- return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+ return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo, env.allocationCallbacks);
}
};
(params.poolSizes.empty() ? DE_NULL : ¶ms.poolSizes[0])
};
- return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo);
+ return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo, env.allocationCallbacks);
}
};
1u // layers
};
- return createFramebuffer(env.vkd, env.device, &framebufferInfo);
+ return createFramebuffer(env.vkd, env.device, &framebufferInfo, env.allocationCallbacks);
}
};
env.queueFamilyIndex,
};
- return createCommandPool(env.vkd, env.device, &cmdPoolInfo);
+ return createCommandPool(env.vkd, env.device, &cmdPoolInfo, env.allocationCallbacks);
}
};
: deviceRes (parent, deviceParams)
, device (Device::create(parent, deviceRes, deviceParams))
, vkd (deviceRes.vki, *device)
- , env (parent.vkp, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, maxResourceConsumers)
+ , env (parent.vkp, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, parent.allocationCallbacks, maxResourceConsumers)
{
}
};
+Device::Parameters getDefaulDeviceParameters (Context& context)
+{
+ return Device::Parameters(context.getTestContext().getCommandLine().getVKDeviceId()-1u,
+ VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
+}
+
template<typename Object>
tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typename Object::Parameters params)
{
typedef SharedPtr<typename Object::Resources> ResPtr;
const deUint32 numThreads = getDefaultTestThreadCount();
- const Device::Parameters deviceParams (context.getTestContext().getCommandLine().getVKDeviceId()-1u, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
+ const Device::Parameters deviceParams = getDefaulDeviceParameters(context);
const Environment sharedEnv (context, numThreads); // For creating Device's
vector<EnvPtr> perThreadEnv (numThreads);
vector<ResPtr> resources (numThreads);
return threads.run();
}
+template<typename Object>
+tcu::TestStatus createSingleAllocCallbacksTest (Context& context, typename Object::Parameters params)
+{
+ const deUint32 noCmdScope = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
+ | VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
+ | VK_SYSTEM_ALLOCATION_SCOPE_CACHE
+ | VK_SYSTEM_ALLOCATION_SCOPE_OBJECT;
+
+ // Callbacks used by resources
+ AllocationCallbackRecorder resCallbacks (getSystemAllocator(), 128);
+
+ // Root environment still uses default instance and device, created without callbacks
+ const Environment rootEnv (context.getPlatformInterface(),
+ context.getDeviceInterface(),
+ context.getDevice(),
+ context.getUniversalQueueFamilyIndex(),
+ context.getBinaryCollection(),
+ resCallbacks.getCallbacks(),
+ 1u);
+
+ {
+ // Test env has instance & device created with callbacks
+ const EnvClone resEnv (rootEnv, getDefaulDeviceParameters(context), 1u);
+ const typename Object::Resources res (resEnv.env, params);
+
+ // Supply a separate callback recorder just for object construction
+ AllocationCallbackRecorder objCallbacks(getSystemAllocator(), 128);
+ const Environment objEnv (resEnv.env.vkp,
+ resEnv.env.vkd,
+ resEnv.env.device,
+ resEnv.env.queueFamilyIndex,
+ resEnv.env.programBinaries,
+ objCallbacks.getCallbacks(),
+ resEnv.env.maxResourceConsumers);
+
+ {
+ Unique<typename Object::Type> obj (Object::create(objEnv, res, params));
+
+ // Validate that no command-level allocations are live
+ if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, noCmdScope))
+ return tcu::TestStatus::fail("Invalid allocation callback");
+ }
+
+ // At this point all allocations made against object callbacks must have been freed
+ if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, 0u))
+ return tcu::TestStatus::fail("Invalid allocation callback");
+ }
+
+ if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
+ return tcu::TestStatus::fail("Invalid allocation callback");
+
+ return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+tcu::TestStatus allocCallbackFailTest (Context& context, typename Object::Parameters params)
+{
+ AllocationCallbackRecorder resCallbacks (getSystemAllocator(), 128);
+ const Environment rootEnv (context.getPlatformInterface(),
+ context.getDeviceInterface(),
+ context.getDevice(),
+ context.getUniversalQueueFamilyIndex(),
+ context.getBinaryCollection(),
+ resCallbacks.getCallbacks(),
+ 1u);
+
+ {
+ const EnvClone resEnv (rootEnv, getDefaulDeviceParameters(context), 1u);
+ const typename Object::Resources res (resEnv.env, params);
+ deUint32 numPassingAllocs = 0;
+ const deUint32 maxTries = 1u<<10;
+
+ // Iterate over test until object allocation succeeds
+ for (; numPassingAllocs < maxTries; ++numPassingAllocs)
+ {
+ DeterministicFailAllocator objAllocator(getSystemAllocator(), numPassingAllocs);
+ AllocationCallbackRecorder recorder (objAllocator.getCallbacks(), 128);
+ const Environment objEnv (resEnv.env.vkp,
+ resEnv.env.vkd,
+ resEnv.env.device,
+ resEnv.env.queueFamilyIndex,
+ resEnv.env.programBinaries,
+ recorder.getCallbacks(),
+ resEnv.env.maxResourceConsumers);
+ bool createOk = false;
+
+ context.getTestContext().getLog()
+ << TestLog::Message
+ << "Trying to create object with " << numPassingAllocs << " allocation" << (numPassingAllocs != 1 ? "s" : "") << " passing"
+ << TestLog::EndMessage;
+
+ try
+ {
+ Unique<typename Object::Type> obj (Object::create(objEnv, res, params));
+ createOk = true;
+ }
+ catch (const vk::OutOfMemoryError& e)
+ {
+ if (e.getError() != VK_ERROR_OUT_OF_HOST_MEMORY)
+ {
+ context.getTestContext().getLog() << e;
+ return tcu::TestStatus::fail("Got invalid error code");
+ }
+ }
+
+ if (!validateAndLog(context.getTestContext().getLog(), recorder, 0u))
+ return tcu::TestStatus::fail("Invalid allocation callback");
+
+ if (createOk)
+ {
+ context.getTestContext().getLog()
+ << TestLog::Message << "Object construction succeeded! " << TestLog::EndMessage;
+ break;
+ }
+ }
+ }
+
+ if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
+ return tcu::TestStatus::fail("Invalid allocation callback");
+
+ return tcu::TestStatus::pass("Ok");
+}
+
// Utilities for creating groups
template<typename Object>
};
objectMgmtTests->addChild(createGroup(testCtx, "multithreaded_shared_resources", "Multithreaded object construction with shared resources", s_multithreadedCreateSharedResourcesGroup));
+ static const CaseDescriptions s_createSingleAllocCallbacksGroup =
+ {
+ CASE_DESC(createSingleAllocCallbacksTest <Instance>, s_instanceCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Device>, s_deviceCases),
+ CASE_DESC(createSingleAllocCallbacksTest <DeviceMemory>, s_deviceMemCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Buffer>, s_bufferCases),
+ CASE_DESC(createSingleAllocCallbacksTest <BufferView>, s_bufferViewCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Image>, s_imageCases),
+ CASE_DESC(createSingleAllocCallbacksTest <ImageView>, s_imageViewCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Semaphore>, s_semaphoreCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Event>, s_eventCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Fence>, s_fenceCases),
+ CASE_DESC(createSingleAllocCallbacksTest <QueryPool>, s_queryPoolCases),
+ CASE_DESC(createSingleAllocCallbacksTest <ShaderModule>, s_shaderModuleCases),
+ CASE_DESC(createSingleAllocCallbacksTest <PipelineCache>, s_pipelineCacheCases),
+ CASE_DESC(createSingleAllocCallbacksTest <PipelineLayout>, s_pipelineLayoutCases),
+ CASE_DESC(createSingleAllocCallbacksTest <RenderPass>, s_renderPassCases),
+ CASE_DESC(createSingleAllocCallbacksTest <GraphicsPipeline>, s_graphicsPipelineCases),
+ CASE_DESC(createSingleAllocCallbacksTest <ComputePipeline>, s_computePipelineCases),
+ CASE_DESC(createSingleAllocCallbacksTest <DescriptorSetLayout>, s_descriptorSetLayoutCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Sampler>, s_samplerCases),
+ CASE_DESC(createSingleAllocCallbacksTest <DescriptorPool>, s_descriptorPoolCases),
+ CASE_DESC(createSingleAllocCallbacksTest <DescriptorSet>, s_descriptorSetCases),
+ CASE_DESC(createSingleAllocCallbacksTest <Framebuffer>, s_framebufferCases),
+ CASE_DESC(createSingleAllocCallbacksTest <CommandPool>, s_commandPoolCases),
+ CASE_DESC(createSingleAllocCallbacksTest <CommandBuffer>, s_commandBufferCases),
+ };
+ objectMgmtTests->addChild(createGroup(testCtx, "single_alloc_callbacks", "Create single object", s_createSingleAllocCallbacksGroup));
+
+ static const CaseDescriptions s_allocCallbackFailGroup =
+ {
+ CASE_DESC(allocCallbackFailTest <Instance>, s_instanceCases),
+ CASE_DESC(allocCallbackFailTest <Device>, s_deviceCases),
+ CASE_DESC(allocCallbackFailTest <DeviceMemory>, s_deviceMemCases),
+ CASE_DESC(allocCallbackFailTest <Buffer>, s_bufferCases),
+ CASE_DESC(allocCallbackFailTest <BufferView>, s_bufferViewCases),
+ CASE_DESC(allocCallbackFailTest <Image>, s_imageCases),
+ CASE_DESC(allocCallbackFailTest <ImageView>, s_imageViewCases),
+ CASE_DESC(allocCallbackFailTest <Semaphore>, s_semaphoreCases),
+ CASE_DESC(allocCallbackFailTest <Event>, s_eventCases),
+ CASE_DESC(allocCallbackFailTest <Fence>, s_fenceCases),
+ CASE_DESC(allocCallbackFailTest <QueryPool>, s_queryPoolCases),
+ CASE_DESC(allocCallbackFailTest <ShaderModule>, s_shaderModuleCases),
+ CASE_DESC(allocCallbackFailTest <PipelineCache>, s_pipelineCacheCases),
+ CASE_DESC(allocCallbackFailTest <PipelineLayout>, s_pipelineLayoutCases),
+ CASE_DESC(allocCallbackFailTest <RenderPass>, s_renderPassCases),
+ CASE_DESC(allocCallbackFailTest <GraphicsPipeline>, s_graphicsPipelineCases),
+ CASE_DESC(allocCallbackFailTest <ComputePipeline>, s_computePipelineCases),
+ CASE_DESC(allocCallbackFailTest <DescriptorSetLayout>, s_descriptorSetLayoutCases),
+ CASE_DESC(allocCallbackFailTest <Sampler>, s_samplerCases),
+ CASE_DESC(allocCallbackFailTest <DescriptorPool>, s_descriptorPoolCases),
+ CASE_DESC(allocCallbackFailTest <DescriptorSet>, s_descriptorSetCases),
+ CASE_DESC(allocCallbackFailTest <Framebuffer>, s_framebufferCases),
+ CASE_DESC(allocCallbackFailTest <CommandPool>, s_commandPoolCases),
+ CASE_DESC(allocCallbackFailTest <CommandBuffer>, s_commandBufferCases),
+ };
+ objectMgmtTests->addChild(createGroup(testCtx, "alloc_callback_fail", "Allocation callback failure", s_allocCallbackFailGroup));
+
return objectMgmtTests.release();
}
#include "vktApiBufferTests.hpp"
#include "vktApiBufferViewCreateTests.hpp"
#include "vktApiBufferViewAccessTests.hpp"
+#include "vktApiFeatureInfo.hpp"
namespace vkt
{
de::MovePtr<tcu::TestCaseGroup> apiTests (new tcu::TestCaseGroup(testCtx, "api", "API Tests"));
apiTests->addChild(createSmokeTests (testCtx));
+ apiTests->addChild(api::createFeatureInfoTests (testCtx));
apiTests->addChild(createDeviceInitializationTests (testCtx));
apiTests->addChild(createObjectManagementTests (testCtx));
apiTests->addChild(createBufferTests (testCtx));
vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
DE_NULL,
(vk::VkSamplerCreateFlags)0,
- vk::mapFilterMode(sampler.magFilter), // magFilter
- vk::mapFilterMode(sampler.minFilter), // minFilter
- vk::mapMipmapMode(sampler.minFilter), // mipMode
- vk::mapWrapMode(sampler.wrapS), // addressU
- vk::mapWrapMode(sampler.wrapT), // addressV
- vk::mapWrapMode(sampler.wrapR), // addressW
- 0.0f, // mipLodBias
- 1, // maxAnisotropy
- (compareEnabled ? vk::VK_TRUE : vk::VK_FALSE), // compareEnable
- compareOp, // compareOp
- 0.0f, // minLod
- 0.0f, // maxLod
- borderColor, // borderColor
- vk::VK_FALSE, // unnormalizedCoords
+ vk::mapFilterMode(sampler.magFilter), // magFilter
+ vk::mapFilterMode(sampler.minFilter), // minFilter
+ vk::mapMipmapMode(sampler.minFilter), // mipMode
+ vk::mapWrapMode(sampler.wrapS), // addressU
+ vk::mapWrapMode(sampler.wrapT), // addressV
+ vk::mapWrapMode(sampler.wrapR), // addressW
+ 0.0f, // mipLodBias
+ 1, // maxAnisotropy
+ (vk::VkBool32)(compareEnabled ? vk::VK_TRUE : vk::VK_FALSE), // compareEnable
+ compareOp, // compareOp
+ 0.0f, // minLod
+ 0.0f, // maxLod
+ borderColor, // borderColor
+ vk::VK_FALSE, // unnormalizedCoords
};
return vk::createSampler(vki, device, &createInfo);
}
vktPipelineBlendTests.hpp
vktPipelineClearUtil.cpp
vktPipelineClearUtil.hpp
+ vktPipelineCombinationsIterator.hpp
vktPipelineDepthTests.cpp
vktPipelineDepthTests.hpp
vktPipelineImageSamplingInstance.cpp
vktPipelineImageSamplingInstance.hpp
vktPipelineImageTests.cpp
vktPipelineImageTests.hpp
+ vktPipelinePushConstantTests.cpp
+ vktPipelinePushConstantTests.hpp
vktPipelineImageUtil.cpp
vktPipelineImageUtil.hpp
vktPipelineImageViewTests.cpp
vktPipelineImageViewTests.hpp
+ vktPipelineMultisampleTests.cpp
+ vktPipelineMultisampleTests.hpp
+ vktPipelineInputAssemblyTests.cpp
+ vktPipelineInputAssemblyTests.hpp
vktPipelineReferenceRenderer.cpp
vktPipelineReferenceRenderer.hpp
vktPipelineSamplerTests.cpp
vktPipelineStencilTests.hpp
vktPipelineTests.cpp
vktPipelineTests.hpp
+ vktPipelineUniqueRandomIterator.hpp
+ vktPipelineVertexInputTests.cpp
+ vktPipelineVertexInputTests.hpp
vktPipelineVertexUtil.cpp
vktPipelineVertexUtil.hpp
)
case TextureFormat::UNORM_INT_1010102_REV:
case TextureFormat::SNORM_INT_1010102_REV:
- threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.1f);
+ threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.34f);
break;
case TextureFormat::UNORM_INT8:
break;
case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
- threshold = Vec4(0.02f, 0.02f, 0.02f, 1.0f);
+ threshold = Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
break;
case TextureFormat::UNSIGNED_INT_999_E5_REV:
--- /dev/null
+#ifndef _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+#define _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Iterator over combinations of items without repetition
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "deRandom.hpp"
+#include <set>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+template <typename T>
+class CombinationsIterator
+{
+public:
+ CombinationsIterator (deUint32 numItems, deUint32 combinationSize);
+ virtual ~CombinationsIterator (void) {}
+ bool hasNext (void) const;
+ T next (void);
+ void reset (void);
+
+protected:
+ virtual T getCombinationValue (const std::vector<deUint32>& combination) = 0;
+
+private:
+ static deUint32 factorial (deUint32 x);
+ deUint32 m_numItems;
+
+ deUint32 m_combinationIndex;
+ deUint32 m_combinationSize;
+ deUint32 m_combinationCount;
+
+ std::vector<deUint32> m_combination;
+};
+
+static deUint32 seriesProduct (deUint32 first, deUint32 last)
+{
+ deUint32 result = 1;
+
+ for (deUint32 i = first; i <= last; i++)
+ result *= i;
+
+ return result;
+}
+
+template <typename T>
+CombinationsIterator<T>::CombinationsIterator (deUint32 numItems, deUint32 combinationSize)
+ : m_numItems (numItems)
+ , m_combinationSize (combinationSize)
+{
+ DE_ASSERT(m_combinationSize > 0);
+ DE_ASSERT(m_combinationSize <= m_numItems);
+
+ m_combinationCount = seriesProduct(numItems - combinationSize + 1, numItems) / seriesProduct(1, combinationSize);
+
+ m_combination.resize(m_combinationSize);
+ reset();
+}
+
+template <typename T>
+bool CombinationsIterator<T>::hasNext (void) const
+{
+ return m_combinationIndex < m_combinationCount;
+}
+
+template <typename T>
+T CombinationsIterator<T>::next (void)
+{
+ DE_ASSERT(m_combinationIndex < m_combinationCount);
+
+ if (m_combinationIndex > 0)
+ {
+ for (int combinationItemNdx = (int)m_combinationSize - 1; combinationItemNdx >= 0; combinationItemNdx--)
+ {
+ if ((m_combination[combinationItemNdx] + 1 < m_numItems) && ((combinationItemNdx == (int)m_combinationSize - 1) || (m_combination[combinationItemNdx + 1] > m_combination[combinationItemNdx] + 1)))
+ {
+ m_combination[combinationItemNdx]++;
+
+ for (deUint32 resetNdx = combinationItemNdx + 1; resetNdx < m_combinationSize; resetNdx++)
+ m_combination[resetNdx] = m_combination[resetNdx - 1] + 1;
+
+ break;
+ }
+ }
+ }
+
+ m_combinationIndex++;
+
+ return getCombinationValue(m_combination);
+}
+
+template <typename T>
+void CombinationsIterator<T>::reset (void)
+{
+ // Set up first combination
+ for (deUint32 itemNdx = 0; itemNdx < m_combinationSize; itemNdx++)
+ m_combination[itemNdx] = itemNdx;
+
+ m_combinationIndex = 0;
+}
+
+template <typename T>
+deUint32 CombinationsIterator<T>::factorial (deUint32 x)
+{
+ deUint32 result = 1;
+
+ for (deUint32 value = x; value > 1; value--)
+ result *= value;
+
+ return result;
+}
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
}
}
-static MovePtr<Program> createRefProgram (const tcu::TextureFormat& renderTargetFormat,
+template<>
+void copySubresourceRange<tcu::Texture3D>(tcu::Texture3D& dest, const tcu::Texture3D& src, const VkImageSubresourceRange& subresourceRange)
+{
+ DE_ASSERT(subresourceRange.levelCount <= (deUint32)dest.getNumLevels());
+ DE_ASSERT(subresourceRange.baseMipLevel + subresourceRange.levelCount <= (deUint32)src.getNumLevels());
+
+ for (int levelNdx = 0; levelNdx < dest.getNumLevels(); levelNdx++)
+ {
+ const tcu::ConstPixelBufferAccess srcLevel(src.getLevel(subresourceRange.baseMipLevel + levelNdx));
+ const tcu::ConstPixelBufferAccess srcLevelLayers(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), (deUint8*)srcLevel.getDataPtr());
+
+ if (dest.isLevelEmpty(levelNdx))
+ dest.allocLevel(levelNdx);
+
+ tcu::copy(dest.getLevel(levelNdx), srcLevelLayers);
+ }
+}
+
+static MovePtr<Program> createRefProgram(const tcu::TextureFormat& renderTargetFormat,
const tcu::Sampler& sampler,
float samplerLod,
const tcu::UVec4& componentMapping,
case VK_IMAGE_TYPE_3D:
{
const tcu::Texture3D& texture = dynamic_cast<const TestTexture3D&>(testTexture).getTexture();
- program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, texture, sampler, samplerLod, componentMapping));
+
+ if (subresource.baseMipLevel > 0)
+ {
+ // Not all texture levels are needed. Create new sub-texture.
+ const tcu::ConstPixelBufferAccess baseLevel = texture.getLevel(subresource.baseMipLevel);
+ tcu::Texture3D textureView(texture.getFormat(), baseLevel.getWidth(), baseLevel.getHeight(), baseLevel.getDepth());
+
+ copySubresourceRange(textureView, texture, subresource);
+
+ program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, textureView, sampler, samplerLod, componentMapping));
+ }
+ else
+ {
+ program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, texture, sampler, samplerLod, componentMapping));
+ }
}
break;
MovePtr<ReferenceRenderer> refRenderer;
// Set up LOD of reference sampler
- if (m_samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_BASE)
- samplerLod = 0.0f;
- else
- samplerLod = de::max(m_samplerParams.minLod, de::min(m_samplerParams.maxLod, m_samplerParams.mipLodBias + m_samplerLod));
+ samplerLod = de::max(m_samplerParams.minLod, de::min(m_samplerParams.maxLod, m_samplerParams.mipLodBias + m_samplerLod));
// Create reference program that uses image subresource range
program = createRefProgram(colorFormat, sampler, samplerLod, componentMapping, *m_texture, m_imageViewType, m_layerCount, m_subresourceRange);
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Input Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineInputAssemblyTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deMath.h"
+#include "deMemory.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+class InputAssemblyTest : public vkt::TestCase
+{
+public:
+ const static VkPrimitiveTopology s_primitiveTopologies[];
+ const static deUint32 s_restartIndex32;
+ const static deUint16 s_restartIndex16;
+
+ InputAssemblyTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology,
+ int primitiveCount,
+ bool testPrimitiveRestart,
+ VkIndexType indexType);
+ virtual ~InputAssemblyTest (void) {}
+ virtual void initPrograms (SourceCollections& sourceCollections) const;
+ virtual TestInstance* createInstance (Context& context) const;
+ static bool isRestartIndex (VkIndexType indexType, deUint32 indexValue);
+ static deUint32 getRestartIndex (VkIndexType indexType);
+
+protected:
+ virtual void createBufferData (VkPrimitiveTopology topology,
+ int primitiveCount,
+ VkIndexType indexType,
+ std::vector<deUint32>& indexData,
+ std::vector<Vertex4RGBA>& vertexData) const = 0;
+
+private:
+ VkPrimitiveTopology m_primitiveTopology;
+ const int m_primitiveCount;
+ bool m_testPrimitiveRestart;
+ VkIndexType m_indexType;
+};
+
+class PrimitiveTopologyTest : public InputAssemblyTest
+{
+public:
+ PrimitiveTopologyTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology);
+ virtual ~PrimitiveTopologyTest (void) {}
+
+protected:
+ virtual void createBufferData (VkPrimitiveTopology topology,
+ int primitiveCount,
+ VkIndexType indexType,
+ std::vector<deUint32>& indexData,
+ std::vector<Vertex4RGBA>& vertexData) const;
+
+private:
+};
+
+class PrimitiveRestartTest : public InputAssemblyTest
+{
+public:
+ PrimitiveRestartTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology,
+ VkIndexType indexType);
+ virtual ~PrimitiveRestartTest (void) {}
+
+protected:
+ virtual void createBufferData (VkPrimitiveTopology topology,
+ int primitiveCount,
+ VkIndexType indexType,
+ std::vector<deUint32>& indexData,
+ std::vector<Vertex4RGBA>& vertexData) const;
+
+private:
+ bool isRestartPrimitive (int primitiveIndex) const;
+
+ std::vector<deUint32> m_restartPrimitives;
+};
+
+class InputAssemblyInstance : public vkt::TestInstance
+{
+public:
+ InputAssemblyInstance (Context& context,
+ VkPrimitiveTopology primitiveTopology,
+ bool testPrimitiveRestart,
+ VkIndexType indexType,
+ const std::vector<deUint32>& indexBufferData,
+ const std::vector<Vertex4RGBA>& vertexBufferData);
+ virtual ~InputAssemblyInstance (void);
+ virtual tcu::TestStatus iterate (void);
+
+private:
+ tcu::TestStatus verifyImage (void);
+ void uploadIndexBufferData16 (deUint16* destPtr, const std::vector<deUint32>& indexBufferData);
+
+ VkPrimitiveTopology m_primitiveTopology;
+ bool m_primitiveRestartEnable;
+ VkIndexType m_indexType;
+
+ Move<VkBuffer> m_vertexBuffer;
+ std::vector<Vertex4RGBA> m_vertices;
+ de::MovePtr<Allocation> m_vertexBufferAlloc;
+
+ Move<VkBuffer> m_indexBuffer;
+ std::vector<deUint32> m_indices;
+ de::MovePtr<Allocation> m_indexBufferAlloc;
+
+ const tcu::IVec2 m_renderSize;
+
+ const VkFormat m_colorFormat;
+ VkImageCreateInfo m_colorImageCreateInfo;
+ Move<VkImage> m_colorImage;
+ de::MovePtr<Allocation> m_colorImageAlloc;
+ Move<VkImageView> m_colorAttachmentView;
+ Move<VkRenderPass> m_renderPass;
+ Move<VkFramebuffer> m_framebuffer;
+
+ Move<VkShaderModule> m_vertexShaderModule;
+ Move<VkShaderModule> m_fragmentShaderModule;
+
+ Move<VkPipelineLayout> m_pipelineLayout;
+ Move<VkPipeline> m_graphicsPipeline;
+
+ Move<VkCommandPool> m_cmdPool;
+ Move<VkCommandBuffer> m_cmdBuffer;
+
+ Move<VkFence> m_fence;
+};
+
+
+// InputAssemblyTest
+
+const VkPrimitiveTopology InputAssemblyTest::s_primitiveTopologies[] =
+{
+ VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
+ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
+ VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
+ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
+};
+
+const deUint32 InputAssemblyTest::s_restartIndex32 = ~((deUint32)0u);
+const deUint16 InputAssemblyTest::s_restartIndex16 = ~((deUint16)0u);
+
+InputAssemblyTest::InputAssemblyTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology,
+ int primitiveCount,
+ bool testPrimitiveRestart,
+ VkIndexType indexType)
+
+ : vkt::TestCase (testContext, name, description)
+ , m_primitiveTopology (primitiveTopology)
+ , m_primitiveCount (primitiveCount)
+ , m_testPrimitiveRestart (testPrimitiveRestart)
+ , m_indexType (indexType)
+{
+}
+
+TestInstance* InputAssemblyTest::createInstance (Context& context) const
+{
+ std::vector<deUint32> indexBufferData;
+ std::vector<Vertex4RGBA> vertexBufferData;
+
+ createBufferData(m_primitiveTopology, m_primitiveCount, m_indexType, indexBufferData, vertexBufferData);
+
+ return new InputAssemblyInstance(context, m_primitiveTopology, m_testPrimitiveRestart, m_indexType, indexBufferData, vertexBufferData);
+}
+
+void InputAssemblyTest::initPrograms (SourceCollections& sourceCollections) const
+{
+ std::ostringstream vertexSource;
+
+ vertexSource <<
+ "#version 310 es\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec4 color;\n"
+ "layout(location = 0) out highp vec4 vtxColor;\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = position;\n"
+ << (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? " gl_PointSize = 3.0;\n"
+ : "" )
+ << " vtxColor = color;\n"
+ "}\n";
+
+ sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
+
+ sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
+ "#version 310 es\n"
+ "layout(location = 0) in highp vec4 vtxColor;\n"
+ "layout(location = 0) out highp vec4 fragColor;\n"
+ "void main (void)\n"
+ "{\n"
+ " fragColor = vtxColor;\n"
+ "}\n");
+}
+
+bool InputAssemblyTest::isRestartIndex (VkIndexType indexType, deUint32 indexValue)
+{
+ if (indexType == VK_INDEX_TYPE_UINT32)
+ return indexValue == s_restartIndex32;
+ else
+ return indexValue == s_restartIndex16;
+}
+
+deUint32 InputAssemblyTest::getRestartIndex (VkIndexType indexType)
+{
+ if (indexType == VK_INDEX_TYPE_UINT16)
+ return InputAssemblyTest::s_restartIndex16;
+ else
+ return InputAssemblyTest::s_restartIndex32;
+}
+
+
+// PrimitiveTopologyTest
+
+PrimitiveTopologyTest::PrimitiveTopologyTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology)
+ : InputAssemblyTest (testContext, name, description, primitiveTopology, 10, false, VK_INDEX_TYPE_UINT32)
+{
+}
+
+void PrimitiveTopologyTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
+{
+ DE_ASSERT(primitiveCount > 0);
+ DE_UNREF(indexType);
+
+ const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
+ const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
+ const float border = 0.2f;
+ const float originX = -1.0f + border;
+ const float originY = -1.0f + border;
+ const Vertex4RGBA defaultVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
+ float primitiveSizeY = (2.0f - 2.0f * border);
+ float primitiveSizeX;
+ std::vector<deUint32> indices;
+ std::vector<Vertex4RGBA> vertices;
+
+
+ // Calculate primitive size
+ switch (topology)
+ {
+ case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
+ case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount - 1);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount + primitiveCount / 2 + primitiveCount % 2 - 1);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+ primitiveSizeX = 1.0f - border;
+ primitiveSizeY = 1.0f - border;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ switch (topology)
+ {
+ case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx);
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((primitiveNdx * 2 + vertexNdx));
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (primitiveNdx == 0)
+ {
+ Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX, originY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(0);
+
+ vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
+ vertices.push_back(vertex);
+ indices.push_back(1);
+ }
+ else
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx + 1);
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx * 3 + vertexNdx);
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (primitiveNdx == 0)
+ {
+ for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(vertexNdx);
+ }
+ }
+ else
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx + 2);
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+ {
+ const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (primitiveNdx == 0)
+ {
+ Vertex4RGBA vertex =
+ {
+ tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(0);
+
+ vertex.position = tcu::Vec4(primitiveSizeX, 0.0f, 0.0f, 1.0f);
+ vertices.push_back(vertex);
+ indices.push_back(1);
+
+ vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle), primitiveSizeY * deFloatSin(stepAngle), 0.0f, 1.0f);
+ vertices.push_back(vertex);
+ indices.push_back(2);
+ }
+ else
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx + 2);
+ }
+ }
+ break;
+ }
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ indices.push_back(0);
+
+ for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx * 2 + vertexNdx + 1);
+ }
+
+ indices.push_back(0);
+ }
+ break;
+
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+ indices.push_back(0);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (primitiveNdx == 0)
+ {
+ Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX, originY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(1);
+
+ vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
+ vertices.push_back(vertex);
+ indices.push_back(2);
+ }
+ else
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx + 2);
+ }
+ }
+
+ indices.push_back(0);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx * 3 + vertexNdx + 1);
+ indices.push_back(0);
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (primitiveNdx == 0)
+ {
+ for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(vertexNdx + 1);
+ indices.push_back(0);
+ }
+ }
+ else
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back(primitiveNdx + 2 + 1);
+ indices.push_back(0);
+ }
+ }
+ break;
+
+ default:
+ DE_ASSERT(false);
+ break;
+ }
+
+ vertexData = vertices;
+ indexData = indices;
+}
+
+
+// PrimitiveRestartTest
+
+PrimitiveRestartTest::PrimitiveRestartTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkPrimitiveTopology primitiveTopology,
+ VkIndexType indexType)
+
+ : InputAssemblyTest (testContext, name, description, primitiveTopology, 10, true, indexType)
+{
+ DE_ASSERT(primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ||
+ primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ||
+ primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN ||
+ primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
+ primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY);
+
+ deUint32 restartPrimitives[] = { 1, 5 };
+
+ m_restartPrimitives = std::vector<deUint32>(restartPrimitives, restartPrimitives + sizeof(restartPrimitives) / sizeof(deUint32));
+}
+
+void PrimitiveRestartTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
+{
+ DE_ASSERT(primitiveCount > 0);
+ DE_UNREF(indexType);
+
+ const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
+ const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
+ const float border = 0.2f;
+ const float originX = -1.0f + border;
+ const float originY = -1.0f + border;
+ const Vertex4RGBA defaultVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
+ float primitiveSizeY = (2.0f - 2.0f * border);
+ float primitiveSizeX;
+ bool primitiveStart = true;
+ std::vector<deUint32> indices;
+ std::vector<Vertex4RGBA> vertices;
+
+
+ // Calculate primitive size
+ switch (topology)
+ {
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+ primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+ primitiveSizeX = 1.0f - border;
+ primitiveSizeY = 1.0f - border;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ switch (topology)
+ {
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (isRestartPrimitive(primitiveNdx))
+ {
+ indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+ primitiveStart = true;
+ }
+ else
+ {
+ if (primitiveStart)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+
+ primitiveStart = false;
+ }
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ }
+ }
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+ {
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (isRestartPrimitive(primitiveNdx))
+ {
+ indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+ primitiveStart = true;
+ }
+ else
+ {
+ if (primitiveStart)
+ {
+ for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ }
+
+ primitiveStart = false;
+ }
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ }
+ }
+ break;
+ }
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+ {
+ const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (isRestartPrimitive(primitiveNdx))
+ {
+ indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+ primitiveStart = true;
+ }
+ else
+ {
+ if (primitiveStart)
+ {
+ Vertex4RGBA vertex =
+ {
+ tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+
+ vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx)), 0.0f, 1.0f),
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+
+ primitiveStart = false;
+ }
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ }
+ }
+ break;
+ }
+
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (isRestartPrimitive(primitiveNdx))
+ {
+ indices.push_back(0);
+ indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+ primitiveStart = true;
+ }
+ else
+ {
+ if (primitiveStart)
+ {
+ indices.push_back(0);
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+
+ primitiveStart = false;
+ }
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ }
+ }
+
+ indices.push_back(0);
+ break;
+
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+ vertices.push_back(defaultVertex);
+
+ for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+ {
+ if (isRestartPrimitive(primitiveNdx))
+ {
+ indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+ primitiveStart = true;
+ }
+ else
+ {
+ if (primitiveStart)
+ {
+ for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+ {
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ indices.push_back(0);
+ }
+
+ primitiveStart = false;
+ }
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+ red
+ };
+
+ vertices.push_back(vertex);
+ indices.push_back((deUint32)vertices.size() - 1);
+ indices.push_back(0);
+ }
+ }
+ break;
+
+ default:
+ DE_ASSERT(false);
+ break;
+ }
+
+ vertexData = vertices;
+ indexData = indices;
+}
+
+bool PrimitiveRestartTest::isRestartPrimitive (int primitiveIndex) const
+{
+ return std::find(m_restartPrimitives.begin(), m_restartPrimitives.end(), primitiveIndex) != m_restartPrimitives.end();
+}
+
+
+// InputAssemblyInstance
+
+InputAssemblyInstance::InputAssemblyInstance (Context& context,
+ VkPrimitiveTopology primitiveTopology,
+ bool testPrimitiveRestart,
+ VkIndexType indexType,
+ const std::vector<deUint32>& indexBufferData,
+ const std::vector<Vertex4RGBA>& vertexBufferData)
+
+ : vkt::TestInstance (context)
+ , m_primitiveTopology (primitiveTopology)
+ , m_primitiveRestartEnable (testPrimitiveRestart)
+ , m_indexType (indexType)
+ , m_vertices (vertexBufferData)
+ , m_indices (indexBufferData)
+ , m_renderSize ((primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) ? tcu::IVec2(32, 32) : tcu::IVec2(64, 16))
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+{
+ const DeviceInterface& vk = context.getDeviceInterface();
+ const VkDevice vkDevice = context.getDevice();
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+ const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+ // Create color image
+ {
+ const VkImageCreateInfo colorImageParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ m_colorFormat, // VkFormat format;
+ { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
+ };
+
+ m_colorImageCreateInfo = colorImageParams;
+ m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+ // Allocate and bind color image memory
+ m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+ VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+ }
+
+ // Create color attachment view
+ {
+ const VkImageViewCreateInfo colorAttachmentViewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ *m_colorImage, // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ m_colorFormat, // VkFormat format;
+ componentMappingRGBA, // VkComponentMapping components;
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange;
+ };
+
+ m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+ }
+
+ // Create render pass
+ {
+ const VkAttachmentDescription colorAttachmentDescription =
+ {
+ 0u, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentReference colorAttachmentReference =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkSubpassDescription subpassDescription =
+ {
+ 0u, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ 0u, // deUint32 inputAttachmentCount;
+ DE_NULL, // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
+ DE_NULL, // const VkAttachmentReference* pResolveAttachments;
+ DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const VkAttachmentReference* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassParams =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkRenderPassCreateFlags flags;
+ 1u, // deUint32 attachmentCount;
+ &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+ }
+
+ // Create framebuffer
+ {
+ const VkFramebufferCreateInfo framebufferParams =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkFramebufferCreateFlags flags;
+ *m_renderPass, // VkRenderPass renderPass;
+ 1u, // deUint32 attachmentCount;
+ &m_colorAttachmentView.get(), // const VkImageView* pAttachments;
+ (deUint32)m_renderSize.x(), // deUint32 width;
+ (deUint32)m_renderSize.y(), // deUint32 height;
+ 1u // deUint32 layers;
+ };
+
+ m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+ }
+
+ // Create pipeline layout
+ {
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineLayoutCreateFlags flags;
+ 0u, // deUint32 setLayoutCount;
+ DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
+ 0u, // deUint32 pushConstantRangeCount;
+ DE_NULL // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+ }
+
+ m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+ m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+ // Create pipeline
+ {
+ const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+ {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
+ *m_vertexShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
+ *m_fragmentShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ }
+ };
+
+ const VkVertexInputBindingDescription vertexInputBindingDescription =
+ {
+ 0u, // deUint32 binding;
+ sizeof(Vertex4RGBA), // deUint32 stride;
+ VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
+ };
+
+ const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
+ {
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ 0u // deUint32 offset;
+ },
+ {
+ 1u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offset;
+ }
+ };
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineVertexInputStateCreateFlags flags;
+ 1u, // deUint32 vertexBindingDescriptionCount;
+ &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
+ 2u, // deUint32 vertexAttributeDescriptionCount;
+ vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
+ };
+
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
+ m_primitiveTopology, // VkPrimitiveTopology topology;
+ m_primitiveRestartEnable // VkBool32 primitiveRestartEnable;
+ };
+
+ const VkViewport viewport =
+ {
+ 0.0f, // float x;
+ 0.0f, // float y;
+ (float)m_renderSize.x(), // float width;
+ (float)m_renderSize.y(), // float height;
+ 0.0f, // float minDepth;
+ 1.0f // float maxDepth;
+ };
+
+ const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+ const VkPipelineViewportStateCreateInfo viewportStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineViewportStateCreateFlags flags;
+ 1u, // deUint32 viewportCount;
+ &viewport, // const VkViewport* pViewports;
+ 1u, // deUint32 scissorCount;
+ &scissor, // const VkRect2D* pScissors;
+ };
+
+ const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineRasterizationStateCreateFlags flags;
+ false, // VkBool32 depthClampEnable;
+ false, // VkBool32 rasterizerDiscardEnable;
+ VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
+ VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FALSE, // VkBool32 depthBiasEnable;
+ 0.0f, // float depthBiasConstantFactor;
+ 0.0f, // float depthBiasClamp;
+ 0.0f, // float depthBiasSlopeFactor;
+ 1.0f // float lineWidth;
+ };
+
+ const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+ {
+ false, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+ };
+
+ const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineColorBlendStateCreateFlags flags;
+ false, // VkBool32 logicOpEnable;
+ VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
+ 1u, // deUint32 attachmentCount;
+ &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
+ { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4];
+ };
+
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDepthStencilStateCreateFlags flags;
+ false, // VkBool32 depthTestEnable;
+ false, // VkBool32 depthWriteEnable;
+ VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
+ false, // VkBool32 depthBoundsTestEnable;
+ false, // VkBool32 stencilTestEnable;
+ // VkStencilOpState front;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ // VkStencilOpState back;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ -1.0f, // float minDepthBounds;
+ +1.0f // float maxDepthBounds;
+ };
+
+ const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDynamicStateCreateFlags flags;
+ 0u, // deUint32 dynamicStateCount;
+ DE_NULL // const VkDynamicState* pDynamicStates;
+ };
+
+ const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+ {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineCreateFlags flags;
+ 2u, // deUint32 stageCount;
+ shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages;
+ &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+ &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+ DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
+ &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+ &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
+ &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
+ *m_pipelineLayout, // VkPipelineLayout layout;
+ *m_renderPass, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ 0u, // VkPipeline basePipelineHandle;
+ 0u // deInt32 basePipelineIndex;
+ };
+
+ m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+ }
+
+ // Create vertex and index buffer
+ {
+ const VkBufferCreateInfo indexBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkBufferCreateFlags flags;
+ m_indices.size() * sizeof(deUint32), // VkDeviceSize size;
+ VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ const VkBufferCreateInfo vertexBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkBufferCreateFlags flags;
+ m_vertices.size() * sizeof(Vertex4RGBA), // VkDeviceSize size;
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ m_indexBuffer = createBuffer(vk, vkDevice, &indexBufferParams);
+ m_indexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_indexBuffer), MemoryRequirement::HostVisible);
+
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_indexBuffer, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset()));
+
+ m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
+ m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+ // Load vertices into index buffer
+ if (m_indexType == VK_INDEX_TYPE_UINT32)
+ {
+ deMemcpy(m_indexBufferAlloc->getHostPtr(), m_indices.data(), m_indices.size() * sizeof(deUint32));
+ }
+ else // m_indexType == VK_INDEX_TYPE_UINT16
+ {
+ uploadIndexBufferData16((deUint16*)m_indexBufferAlloc->getHostPtr(), m_indices);
+ }
+
+ // Load vertices into vertex buffer
+ deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+
+ // Flush memory
+ const VkMappedMemoryRange flushMemoryRanges[] =
+ {
+ {
+ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ m_indexBufferAlloc->getMemory(), // VkDeviceMemory memory;
+ m_indexBufferAlloc->getOffset(), // VkDeviceSize offset;
+ indexBufferParams.size // VkDeviceSize size;
+ },
+ {
+ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ m_vertexBufferAlloc->getMemory(), // VkDeviceMemory memory;
+ m_vertexBufferAlloc->getOffset(), // VkDeviceSize offset;
+ vertexBufferParams.size // VkDeviceSize size;
+ },
+ };
+
+ vk.flushMappedMemoryRanges(vkDevice, 2, flushMemoryRanges);
+ }
+
+ // Create command pool
+ {
+ const VkCommandPoolCreateInfo cmdPoolParams =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
+ queueFamilyIndex // deUint32 queueFamilyIndex;
+ };
+
+ m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+ }
+
+ // Create command buffer
+ {
+ const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_cmdPool, // VkCommandPool commandPool;
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
+ 1u // deUint32 bufferCount;
+ };
+
+ const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkCommandBufferUsageFlags flags;
+ DE_NULL, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkFramebuffer framebuffer;
+ false, // VkBool32 occlusionQueryEnable;
+ 0u, // VkQueryControlFlags queryFlags;
+ 0u // VkQueryPipelineStatisticFlags pipelineStatistics;
+ };
+
+ const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
+
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_renderPass, // VkRenderPass renderPass;
+ *m_framebuffer, // VkFramebuffer framebuffer;
+ { { 0, 0 } , { m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea;
+ 1u, // deUint32 clearValueCount;
+ &attachmentClearValue // const VkClearValue* pClearValues;
+ };
+
+ m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+ VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+ vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ const VkDeviceSize vertexBufferOffset = 0;
+
+ vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+ vk.cmdBindIndexBuffer(*m_cmdBuffer, *m_indexBuffer, 0, m_indexType);
+ vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indices.size(), 1, 0, 0, 0);
+
+ vk.cmdEndRenderPass(*m_cmdBuffer);
+ VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+ }
+
+ // Create fence
+ {
+ const VkFenceCreateInfo fenceParams =
+ {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u // VkFenceCreateFlags flags;
+ };
+
+ m_fence = createFence(vk, vkDevice, &fenceParams);
+ }
+}
+
+InputAssemblyInstance::~InputAssemblyInstance (void)
+{
+}
+
+tcu::TestStatus InputAssemblyInstance::iterate (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // deUint32 waitSemaphoreCount;
+ DE_NULL, // const VkSemaphore* pWaitSemaphores;
+ 1u, // deUint32 commandBufferCount;
+ &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
+ 0u, // deUint32 signalSemaphoreCount;
+ DE_NULL // const VkSemaphore* pSignalSemaphores;
+ };
+
+ VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+ VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+ VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+ return verifyImage();
+}
+
+tcu::TestStatus InputAssemblyInstance::verifyImage (void)
+{
+ const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
+ const tcu::TextureFormat tcuStencilFormat = tcu::TextureFormat();
+ const ColorVertexShader vertexShader;
+ const ColorFragmentShader fragmentShader (tcuColorFormat, tcuStencilFormat);
+ const rr::Program program (&vertexShader, &fragmentShader);
+ ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
+ bool compareOk = false;
+
+ // Render reference image
+ {
+ const rr::PrimitiveType topology = mapVkPrimitiveTopology(m_primitiveTopology);
+ rr::RenderState renderState (refRenderer.getViewportState());
+
+
+ if (m_primitiveRestartEnable)
+ {
+ std::vector<deUint32> indicesRange;
+
+ for (size_t indexNdx = 0; indexNdx < m_indices.size(); indexNdx++)
+ {
+ const bool isRestart = InputAssemblyTest::isRestartIndex(m_indexType, m_indices[indexNdx]);
+
+ if (!isRestart)
+ indicesRange.push_back(m_indices[indexNdx]);
+
+ if (isRestart || indexNdx == (m_indices.size() - 1))
+ {
+ // Draw the range of indices found so far
+
+ std::vector<Vertex4RGBA> nonIndexedVertices;
+ for (size_t i = 0; i < indicesRange.size(); i++)
+ nonIndexedVertices.push_back(m_vertices[indicesRange[i]]);
+
+ refRenderer.draw(renderState, topology, nonIndexedVertices);
+ indicesRange.clear();
+ }
+ }
+ }
+ else
+ {
+ std::vector<Vertex4RGBA> nonIndexedVertices;
+ for (size_t i = 0; i < m_indices.size(); i++)
+ nonIndexedVertices.push_back(m_vertices[m_indices[i]]);
+
+ refRenderer.draw(renderState, topology, nonIndexedVertices);
+ }
+ }
+
+ // Compare result with reference image
+ {
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+ de::UniquePtr<tcu::TextureLevel> result (readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
+
+ compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+ "IntImageCompare",
+ "Image comparison",
+ refRenderer.getAccess(),
+ result->getAccess(),
+ tcu::UVec4(2, 2, 2, 2),
+ tcu::IVec3(1, 1, 0),
+ true,
+ tcu::COMPARE_LOG_RESULT);
+ }
+
+ if (compareOk)
+ return tcu::TestStatus::pass("Result image matches reference");
+ else
+ return tcu::TestStatus::fail("Image mismatch");
+}
+
+void InputAssemblyInstance::uploadIndexBufferData16 (deUint16* destPtr, const std::vector<deUint32>& indexBufferData)
+{
+ for (size_t i = 0; i < indexBufferData.size(); i++)
+ {
+ DE_ASSERT(indexBufferData[i] <= 0xFFFF);
+ destPtr[i] = (deUint16)indexBufferData[i];
+ }
+}
+
+
+// Utilities for test names
+
+std::string getPrimitiveTopologyCaseName (VkPrimitiveTopology topology)
+{
+ const std::string fullName = getPrimitiveTopologyName(topology);
+
+ DE_ASSERT(de::beginsWith(fullName, "VK_PRIMITIVE_TOPOLOGY_"));
+
+ return de::toLower(fullName.substr(22));
+}
+
+de::MovePtr<tcu::TestCaseGroup> createPrimitiveTopologyTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> primitiveTopologyTests (new tcu::TestCaseGroup(testCtx, "primitive_topology", ""));
+
+ for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(InputAssemblyTest::s_primitiveTopologies); topologyNdx++)
+ {
+ const VkPrimitiveTopology topology = InputAssemblyTest::s_primitiveTopologies[topologyNdx];
+
+ primitiveTopologyTests->addChild(new PrimitiveTopologyTest(testCtx,
+ getPrimitiveTopologyCaseName(topology),
+ "",
+ topology));
+ }
+
+ return primitiveTopologyTests;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createPrimitiveRestartTests (tcu::TestContext& testCtx)
+{
+ const VkPrimitiveTopology primitiveRestartTopologies[] =
+ {
+ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
+ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> primitiveRestartTests (new tcu::TestCaseGroup(testCtx, "primitive_restart", "Restarts indices of "));
+
+ de::MovePtr<tcu::TestCaseGroup> indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16", ""));
+ de::MovePtr<tcu::TestCaseGroup> indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32", ""));
+
+ for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(primitiveRestartTopologies); topologyNdx++)
+ {
+ const VkPrimitiveTopology topology = primitiveRestartTopologies[topologyNdx];
+
+ indexUint16Tests->addChild(new PrimitiveRestartTest(testCtx,
+ getPrimitiveTopologyCaseName(topology),
+ "",
+ topology,
+ VK_INDEX_TYPE_UINT16));
+
+ indexUint32Tests->addChild(new PrimitiveRestartTest(testCtx,
+ getPrimitiveTopologyCaseName(topology),
+ "",
+ topology,
+ VK_INDEX_TYPE_UINT32));
+ }
+
+ primitiveRestartTests->addChild(indexUint16Tests.release());
+ primitiveRestartTests->addChild(indexUint32Tests.release());
+
+ return primitiveRestartTests;
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> inputAssemblyTests (new tcu::TestCaseGroup(testCtx, "input_assembly", "Input assembly tests"));
+
+ inputAssemblyTests->addChild(createPrimitiveTopologyTests(testCtx).release());
+ inputAssemblyTests->addChild(createPrimitiveRestartTests(testCtx).release());
+
+ return inputAssemblyTests.release();
+}
+
+} // pipeline
+} // vkt
--- /dev/null
+#ifndef _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
+#define _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Input Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Multisample Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineMultisampleTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deMemory.h"
+
+#include <sstream>
+#include <vector>
+#include <map>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+enum GeometryType
+{
+ GEOMETRY_TYPE_OPAQUE_TRIANGLE,
+ GEOMETRY_TYPE_OPAQUE_LINE,
+ GEOMETRY_TYPE_OPAQUE_POINT,
+ GEOMETRY_TYPE_OPAQUE_QUAD,
+ GEOMETRY_TYPE_TRANSLUCENT_QUAD,
+ GEOMETRY_TYPE_INVISIBLE_QUAD,
+ GEOMETRY_TYPE_GRADIENT_QUAD
+};
+
+
+bool isSupportedSampleCount (const InstanceInterface& instanceInterface, VkPhysicalDevice physicalDevice, VkSampleCountFlagBits rasterizationSamples);
+VkPipelineColorBlendAttachmentState getDefaultColorBlendAttachmentState (void);
+deUint32 getUniqueColorsCount (const tcu::ConstPixelBufferAccess& image);
+void initMultisamplePrograms (SourceCollections& sources, GeometryType geometryType);
+
+class MultisampleTest : public vkt::TestCase
+{
+public:
+
+ MultisampleTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState,
+ GeometryType geometryType);
+ virtual ~MultisampleTest (void);
+
+ virtual void initPrograms (SourceCollections& programCollection) const;
+ virtual TestInstance* createInstance (Context& context) const;
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const = 0;
+ VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+ const GeometryType m_geometryType;
+ std::vector<VkSampleMask> m_sampleMask;
+};
+
+class RasterizationSamplesTest : public MultisampleTest
+{
+public:
+ RasterizationSamplesTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ GeometryType geometryType);
+ virtual ~RasterizationSamplesTest (void) {}
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const;
+
+ static VkPipelineMultisampleStateCreateInfo getRasterizationSamplesStateParams (VkSampleCountFlagBits rasterizationSamples);
+};
+
+class MinSampleShadingTest : public MultisampleTest
+{
+public:
+ MinSampleShadingTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ float minSampleShading,
+ GeometryType geometryType);
+ virtual ~MinSampleShadingTest (void) {}
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const;
+
+ static VkPipelineMultisampleStateCreateInfo getMinSampleShadingStateParams (VkSampleCountFlagBits rasterizationSamples, float minSampleShading);
+};
+
+class SampleMaskTest : public MultisampleTest
+{
+public:
+ SampleMaskTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ const std::vector<VkSampleMask>& sampleMask,
+ GeometryType geometryType);
+
+ virtual ~SampleMaskTest (void) {}
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const;
+
+ static VkPipelineMultisampleStateCreateInfo getSampleMaskStateParams (VkSampleCountFlagBits rasterizationSamples, const std::vector<VkSampleMask>& sampleMask);
+};
+
+class AlphaToOneTest : public MultisampleTest
+{
+public:
+ AlphaToOneTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples);
+
+ virtual ~AlphaToOneTest (void) {}
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const;
+
+ static VkPipelineMultisampleStateCreateInfo getAlphaToOneStateParams (VkSampleCountFlagBits rasterizationSamples);
+ static VkPipelineColorBlendAttachmentState getAlphaToOneBlendState (void);
+};
+
+class AlphaToCoverageTest : public MultisampleTest
+{
+public:
+ AlphaToCoverageTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ GeometryType geometryType);
+
+ virtual ~AlphaToCoverageTest (void) {}
+
+protected:
+ virtual TestInstance* createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const;
+
+ static VkPipelineMultisampleStateCreateInfo getAlphaToCoverageStateParams (VkSampleCountFlagBits rasterizationSamples);
+
+ GeometryType m_geometryType;
+};
+
+class MultisampleRenderer
+{
+public:
+ MultisampleRenderer (Context& context,
+ VkFormat colorFormat,
+ const tcu::IVec2& renderSize,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState);
+
+ virtual ~MultisampleRenderer (void);
+
+ de::MovePtr<tcu::TextureLevel> render (void);
+
+protected:
+ Context& m_context;
+
+ const VkFormat m_colorFormat;
+ tcu::IVec2 m_renderSize;
+
+ const VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+
+ Move<VkImage> m_colorImage;
+ de::MovePtr<Allocation> m_colorImageAlloc;
+ Move<VkImageView> m_colorAttachmentView;
+
+ Move<VkImage> m_resolveImage;
+ de::MovePtr<Allocation> m_resolveImageAlloc;
+ Move<VkImageView> m_resolveAttachmentView;
+
+ Move<VkRenderPass> m_renderPass;
+ Move<VkFramebuffer> m_framebuffer;
+
+ Move<VkShaderModule> m_vertexShaderModule;
+ Move<VkShaderModule> m_fragmentShaderModule;
+
+ Move<VkBuffer> m_vertexBuffer;
+ de::MovePtr<Allocation> m_vertexBufferAlloc;
+
+ Move<VkPipelineLayout> m_pipelineLayout;
+ Move<VkPipeline> m_graphicsPipeline;
+
+ Move<VkCommandPool> m_cmdPool;
+ Move<VkCommandBuffer> m_cmdBuffer;
+
+ Move<VkFence> m_fence;
+};
+
+class RasterizationSamplesInstance : public vkt::TestInstance
+{
+public:
+ RasterizationSamplesInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState);
+ virtual ~RasterizationSamplesInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ virtual tcu::TestStatus verifyImage (const tcu::ConstPixelBufferAccess& result);
+
+ const VkFormat m_colorFormat;
+ const tcu::IVec2 m_renderSize;
+ const VkPrimitiveTopology m_primitiveTopology;
+ const std::vector<Vertex4RGBA> m_vertices;
+ MultisampleRenderer m_multisampleRenderer;
+};
+
+class MinSampleShadingInstance : public vkt::TestInstance
+{
+public:
+ MinSampleShadingInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState);
+ virtual ~MinSampleShadingInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ virtual tcu::TestStatus verifyImage (const tcu::ConstPixelBufferAccess& testShadingImage,
+ const tcu::ConstPixelBufferAccess& minShadingImage,
+ const tcu::ConstPixelBufferAccess& maxShadingImage);
+ const VkFormat m_colorFormat;
+ const tcu::IVec2 m_renderSize;
+ const VkPrimitiveTopology m_primitiveTopology;
+ const std::vector<Vertex4RGBA> m_vertices;
+ const VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+};
+
+class SampleMaskInstance : public vkt::TestInstance
+{
+public:
+ SampleMaskInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState);
+ virtual ~SampleMaskInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ virtual tcu::TestStatus verifyImage (const tcu::ConstPixelBufferAccess& testShadingImage,
+ const tcu::ConstPixelBufferAccess& minShadingImage,
+ const tcu::ConstPixelBufferAccess& maxShadingImage);
+ const VkFormat m_colorFormat;
+ const tcu::IVec2 m_renderSize;
+ const VkPrimitiveTopology m_primitiveTopology;
+ const std::vector<Vertex4RGBA> m_vertices;
+ const VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+};
+
+class AlphaToOneInstance : public vkt::TestInstance
+{
+public:
+ AlphaToOneInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState);
+ virtual ~AlphaToOneInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ virtual tcu::TestStatus verifyImage (const tcu::ConstPixelBufferAccess& alphaOneImage,
+ const tcu::ConstPixelBufferAccess& noAlphaOneImage);
+ const VkFormat m_colorFormat;
+ const tcu::IVec2 m_renderSize;
+ const VkPrimitiveTopology m_primitiveTopology;
+ const std::vector<Vertex4RGBA> m_vertices;
+ const VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+};
+
+class AlphaToCoverageInstance : public vkt::TestInstance
+{
+public:
+ AlphaToCoverageInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState,
+ GeometryType geometryType);
+ virtual ~AlphaToCoverageInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ virtual tcu::TestStatus verifyImage (const tcu::ConstPixelBufferAccess& result);
+ const VkFormat m_colorFormat;
+ const tcu::IVec2 m_renderSize;
+ const VkPrimitiveTopology m_primitiveTopology;
+ const std::vector<Vertex4RGBA> m_vertices;
+ const VkPipelineMultisampleStateCreateInfo m_multisampleStateParams;
+ const VkPipelineColorBlendAttachmentState m_colorBlendState;
+ const GeometryType m_geometryType;
+};
+
+
+// Helper functions
+
+void initMultisamplePrograms (SourceCollections& sources, GeometryType geometryType)
+{
+ std::ostringstream vertexSource;
+
+ vertexSource <<
+ "#version 310 es\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec4 color;\n"
+ "layout(location = 0) out highp vec4 vtxColor;\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = position;\n"
+ " vtxColor = color;\n"
+ << (geometryType == GEOMETRY_TYPE_OPAQUE_POINT ? " gl_PointSize = 3.0f;\n"
+ : "" )
+ << "}\n";
+
+ static const char* fragmentSource =
+ "#version 310 es\n"
+ "layout(location = 0) in highp vec4 vtxColor;\n"
+ "layout(location = 0) out highp vec4 fragColor;\n"
+ "void main (void)\n"
+ "{\n"
+ " fragColor = vtxColor;\n"
+ "}\n";
+
+ sources.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
+ sources.glslSources.add("color_frag") << glu::FragmentSource(fragmentSource);
+}
+
+bool isSupportedSampleCount (const InstanceInterface& instanceInterface, VkPhysicalDevice physicalDevice, VkSampleCountFlagBits rasterizationSamples)
+{
+ VkPhysicalDeviceProperties deviceProperties;
+
+ instanceInterface.getPhysicalDeviceProperties(physicalDevice, &deviceProperties);
+
+ return !!(deviceProperties.limits.framebufferColorSampleCounts & rasterizationSamples);
+}
+
+VkPipelineColorBlendAttachmentState getDefaultColorBlendAttachmentState (void)
+{
+ const VkPipelineColorBlendAttachmentState colorBlendState =
+ {
+ false, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+ };
+
+ return colorBlendState;
+}
+
+deUint32 getUniqueColorsCount (const tcu::ConstPixelBufferAccess& image)
+{
+ DE_ASSERT(image.getFormat().getPixelSize() == 4);
+
+ std::map<deUint32, deUint32> histogram; // map<pixel value, number of occurrences>
+ const deUint32 pixelCount = image.getWidth() * image.getHeight() * image.getDepth();
+
+ for (deUint32 pixelNdx = 0; pixelNdx < pixelCount; pixelNdx++)
+ {
+ const deUint32 pixelValue = *((const deUint32*)image.getDataPtr() + pixelNdx);
+
+ if (histogram.find(pixelValue) != histogram.end())
+ histogram[pixelValue]++;
+ else
+ histogram[pixelValue] = 1;
+ }
+
+ return (deUint32)histogram.size();
+}
+
+
+// MultisampleTest
+
+MultisampleTest::MultisampleTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState,
+ GeometryType geometryType)
+ : vkt::TestCase (testContext, name, description)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (blendState)
+ , m_geometryType (geometryType)
+{
+ if (m_multisampleStateParams.pSampleMask)
+ {
+ // Copy pSampleMask to avoid dependencies with other classes
+
+ const deUint32 maskCount = m_multisampleStateParams.rasterizationSamples / 32;
+
+ for (deUint32 maskNdx = 0; maskNdx < maskCount; maskNdx++)
+ m_sampleMask.push_back(m_multisampleStateParams.pSampleMask[maskNdx]);
+
+ m_multisampleStateParams.pSampleMask = m_sampleMask.data();
+ }
+}
+
+MultisampleTest::~MultisampleTest (void)
+{
+}
+
+void MultisampleTest::initPrograms (SourceCollections& programCollection) const
+{
+ initMultisamplePrograms(programCollection, m_geometryType);
+}
+
+TestInstance* MultisampleTest::createInstance (Context& context) const
+{
+ VkPrimitiveTopology topology;
+ std::vector<Vertex4RGBA> vertices;
+
+ switch (m_geometryType)
+ {
+ case GEOMETRY_TYPE_OPAQUE_TRIANGLE:
+ {
+ topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ const Vertex4RGBA vertexData[3] =
+ {
+ {
+ tcu::Vec4(-0.75f, 0.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(0.75f, 0.125f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(0.75f, -0.125f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ }
+ };
+
+ vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 3);
+ break;
+ }
+
+ case GEOMETRY_TYPE_OPAQUE_LINE:
+ {
+ topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+
+ const Vertex4RGBA vertexData[2] =
+ {
+ {
+ tcu::Vec4(-0.75f, 0.25f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(0.75f, -0.25f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ }
+ };
+
+ vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 2);
+ break;
+ }
+
+ case GEOMETRY_TYPE_OPAQUE_POINT:
+ {
+ topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+
+ const Vertex4RGBA vertex =
+ {
+ tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ };
+
+ vertices = std::vector<Vertex4RGBA>(1, vertex);
+ break;
+ }
+
+ case GEOMETRY_TYPE_OPAQUE_QUAD:
+ case GEOMETRY_TYPE_TRANSLUCENT_QUAD:
+ case GEOMETRY_TYPE_INVISIBLE_QUAD:
+ case GEOMETRY_TYPE_GRADIENT_QUAD:
+ {
+ topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+
+ Vertex4RGBA vertexData[4] =
+ {
+ {
+ tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ }
+ };
+
+ if (m_geometryType == GEOMETRY_TYPE_TRANSLUCENT_QUAD)
+ {
+ for (int i = 0; i < 4; i++)
+ vertexData[i].color.w() = 0.25f;
+ }
+ else if (m_geometryType == GEOMETRY_TYPE_INVISIBLE_QUAD)
+ {
+ for (int i = 0; i < 4; i++)
+ vertexData[i].color.w() = 0.0f;
+ }
+ else if (m_geometryType == GEOMETRY_TYPE_GRADIENT_QUAD)
+ {
+ vertexData[0].color.w() = 0.0f;
+ vertexData[2].color.w() = 0.0f;
+ }
+
+ vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 4);
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ return createMultisampleTestInstance(context, topology, vertices, m_multisampleStateParams, m_colorBlendState);
+}
+
+
+// RasterizationSamplesTest
+
+RasterizationSamplesTest::RasterizationSamplesTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ GeometryType geometryType)
+ : MultisampleTest (testContext, name, description, getRasterizationSamplesStateParams(rasterizationSamples), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+VkPipelineMultisampleStateCreateInfo RasterizationSamplesTest::getRasterizationSamplesStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ rasterizationSamples, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ return multisampleStateParams;
+}
+
+TestInstance* RasterizationSamplesTest::createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const
+{
+ return new RasterizationSamplesInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+
+// MinSampleShadingTest
+
+MinSampleShadingTest::MinSampleShadingTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ float minSampleShading,
+ GeometryType geometryType)
+ : MultisampleTest (testContext, name, description, getMinSampleShadingStateParams(rasterizationSamples, minSampleShading), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+TestInstance* MinSampleShadingTest::createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const
+{
+ return new MinSampleShadingInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo MinSampleShadingTest::getMinSampleShadingStateParams (VkSampleCountFlagBits rasterizationSamples, float minSampleShading)
+{
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ rasterizationSamples, // VkSampleCountFlagBits rasterizationSamples;
+ true, // VkBool32 sampleShadingEnable;
+ minSampleShading, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ return multisampleStateParams;
+}
+
+
+// SampleMaskTest
+
+SampleMaskTest::SampleMaskTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ const std::vector<VkSampleMask>& sampleMask,
+ GeometryType geometryType)
+ : MultisampleTest (testContext, name, description, getSampleMaskStateParams(rasterizationSamples, sampleMask), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+TestInstance* SampleMaskTest::createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const
+{
+ return new SampleMaskInstance(context, topology,vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo SampleMaskTest::getSampleMaskStateParams (VkSampleCountFlagBits rasterizationSamples, const std::vector<VkSampleMask>& sampleMask)
+{
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ rasterizationSamples, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ sampleMask.data(), // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ return multisampleStateParams;
+}
+
+
+// AlphaToOneTest
+
+AlphaToOneTest::AlphaToOneTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples)
+ : MultisampleTest (testContext, name, description, getAlphaToOneStateParams(rasterizationSamples), getAlphaToOneBlendState(), GEOMETRY_TYPE_GRADIENT_QUAD)
+{
+}
+
+TestInstance* AlphaToOneTest::createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const
+{
+ return new AlphaToOneInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo AlphaToOneTest::getAlphaToOneStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ rasterizationSamples, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ true // VkBool32 alphaToOneEnable;
+ };
+
+ return multisampleStateParams;
+}
+
+VkPipelineColorBlendAttachmentState AlphaToOneTest::getAlphaToOneBlendState (void)
+{
+ const VkPipelineColorBlendAttachmentState colorBlendState =
+ {
+ true, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+ };
+
+ return colorBlendState;
+}
+
+
+// AlphaToCoverageTest
+
+AlphaToCoverageTest::AlphaToCoverageTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ VkSampleCountFlagBits rasterizationSamples,
+ GeometryType geometryType)
+ : MultisampleTest (testContext, name, description, getAlphaToCoverageStateParams(rasterizationSamples), getDefaultColorBlendAttachmentState(), geometryType)
+ , m_geometryType (geometryType)
+{
+}
+
+TestInstance* AlphaToCoverageTest::createMultisampleTestInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState) const
+{
+ return new AlphaToCoverageInstance(context, topology, vertices, multisampleStateParams, colorBlendState, m_geometryType);
+}
+
+VkPipelineMultisampleStateCreateInfo AlphaToCoverageTest::getAlphaToCoverageStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ rasterizationSamples, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ true, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ return multisampleStateParams;
+}
+
+// RasterizationSamplesInstance
+
+RasterizationSamplesInstance::RasterizationSamplesInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState)
+ : vkt::TestInstance (context)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_renderSize (32, 32)
+ , m_primitiveTopology (topology)
+ , m_vertices (vertices)
+ , m_multisampleRenderer (context, m_colorFormat, m_renderSize, topology, vertices, multisampleStateParams, blendState)
+{
+}
+
+tcu::TestStatus RasterizationSamplesInstance::iterate (void)
+{
+ de::MovePtr<tcu::TextureLevel> level(m_multisampleRenderer.render());
+ return verifyImage(level->getAccess());
+}
+
+tcu::TestStatus RasterizationSamplesInstance::verifyImage (const tcu::ConstPixelBufferAccess& result)
+{
+ // Verify range of unique pixels
+ {
+ const deUint32 numUniqueColors = getUniqueColorsCount(result);
+ const deUint32 minUniqueColors = 3;
+
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+
+ log << tcu::TestLog::Message
+ << "\nMin. unique colors expected: " << minUniqueColors << "\n"
+ << "Unique colors found: " << numUniqueColors << "\n"
+ << tcu::TestLog::EndMessage;
+
+ if (numUniqueColors < minUniqueColors)
+ return tcu::TestStatus::fail("Unique colors out of expected bounds");
+ }
+
+ // Verify shape of the rendered primitive (fuzzy-compare)
+ {
+ const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
+ const tcu::TextureFormat tcuDepthFormat = tcu::TextureFormat();
+ const ColorVertexShader vertexShader;
+ const ColorFragmentShader fragmentShader (tcuColorFormat, tcuDepthFormat);
+ const rr::Program program (&vertexShader, &fragmentShader);
+ ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+ rr::RenderState renderState (refRenderer.getViewportState());
+
+ if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
+ {
+ VkPhysicalDeviceProperties deviceProperties;
+
+ m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &deviceProperties);
+
+ // gl_PointSize is clamped to pointSizeRange
+ renderState.point.pointSize = deFloatMin(3.0f, deviceProperties.limits.pointSizeRange[1]);
+ }
+
+ refRenderer.colorClear(tcu::Vec4(0.0f));
+ refRenderer.draw(renderState, mapVkPrimitiveTopology(m_primitiveTopology), m_vertices);
+
+ if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "FuzzyImageCompare", "Image comparison", refRenderer.getAccess(), result, 0.05f, tcu::COMPARE_LOG_RESULT))
+ return tcu::TestStatus::fail("Primitive has unexpected shape");
+
+ }
+
+ return tcu::TestStatus::pass("Primitive rendered, unique colors within expected bounds");
+}
+
+
+// MinSampleShadingInstance
+
+MinSampleShadingInstance::MinSampleShadingInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& colorBlendState)
+ : vkt::TestInstance (context)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_renderSize (32, 32)
+ , m_primitiveTopology (topology)
+ , m_vertices (vertices)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (colorBlendState)
+{
+ VkPhysicalDeviceFeatures deviceFeatures;
+
+ m_context.getInstanceInterface().getPhysicalDeviceFeatures(m_context.getPhysicalDevice(), &deviceFeatures);
+
+ if (!deviceFeatures.sampleRateShading)
+ throw tcu::NotSupportedError("Sample shading is not supported");
+}
+
+tcu::TestStatus MinSampleShadingInstance::iterate (void)
+{
+ de::MovePtr<tcu::TextureLevel> testShadingImage;
+ de::MovePtr<tcu::TextureLevel> minShadingImage;
+ de::MovePtr<tcu::TextureLevel> maxShadingImage;
+
+ // Render with test minSampleShading
+ {
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+ testShadingImage = renderer.render();
+ }
+
+ // Render with minSampleShading = 0.0f
+ {
+ VkPipelineMultisampleStateCreateInfo multisampleParams = m_multisampleStateParams;
+ multisampleParams.minSampleShading = 0.0f;
+
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+ minShadingImage = renderer.render();
+ }
+
+ // Render with minSampleShading = 1.0f
+ {
+ VkPipelineMultisampleStateCreateInfo multisampleParams = m_multisampleStateParams;
+ multisampleParams.minSampleShading = 1.0f;
+
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+ maxShadingImage = renderer.render();
+ }
+
+ return verifyImage(testShadingImage->getAccess(), minShadingImage->getAccess(), maxShadingImage->getAccess());
+}
+
+tcu::TestStatus MinSampleShadingInstance::verifyImage (const tcu::ConstPixelBufferAccess& testShadingImage, const tcu::ConstPixelBufferAccess& minShadingImage, const tcu::ConstPixelBufferAccess& maxShadingImage)
+{
+ const deUint32 testColorCount = getUniqueColorsCount(testShadingImage);
+ const deUint32 minColorCount = getUniqueColorsCount(minShadingImage);
+ const deUint32 maxColorCount = getUniqueColorsCount(maxShadingImage);
+
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+
+ log << tcu::TestLog::Message
+ << "\nColors found: " << testColorCount << "\n"
+ << "Min. colors expected: " << minColorCount << "\n"
+ << "Max. colors expected: " << maxColorCount << "\n"
+ << tcu::TestLog::EndMessage;
+
+ if (minColorCount > testColorCount || testColorCount > maxColorCount)
+ return tcu::TestStatus::fail("Unique colors out of expected bounds");
+ else
+ return tcu::TestStatus::pass("Unique colors within expected bounds");
+}
+
+SampleMaskInstance::SampleMaskInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState)
+ : vkt::TestInstance (context)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_renderSize (32, 32)
+ , m_primitiveTopology (topology)
+ , m_vertices (vertices)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (blendState)
+{
+}
+
+tcu::TestStatus SampleMaskInstance::iterate (void)
+{
+ de::MovePtr<tcu::TextureLevel> testSampleMaskImage;
+ de::MovePtr<tcu::TextureLevel> minSampleMaskImage;
+ de::MovePtr<tcu::TextureLevel> maxSampleMaskImage;
+
+ // Render with test flags
+ {
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+ testSampleMaskImage = renderer.render();
+ }
+
+ // Render with all flags off
+ {
+ VkPipelineMultisampleStateCreateInfo multisampleParams = m_multisampleStateParams;
+ const std::vector<VkSampleMask> sampleMask (multisampleParams.rasterizationSamples / 32, (VkSampleMask)0);
+
+ multisampleParams.pSampleMask = sampleMask.data();
+
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+ minSampleMaskImage = renderer.render();
+ }
+
+ // Render with all flags on
+ {
+ VkPipelineMultisampleStateCreateInfo multisampleParams = m_multisampleStateParams;
+ const std::vector<VkSampleMask> sampleMask (multisampleParams.rasterizationSamples / 32, ~((VkSampleMask)0));
+
+ multisampleParams.pSampleMask = sampleMask.data();
+
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+ maxSampleMaskImage = renderer.render();
+ }
+
+ return verifyImage(testSampleMaskImage->getAccess(), minSampleMaskImage->getAccess(), maxSampleMaskImage->getAccess());
+}
+
+tcu::TestStatus SampleMaskInstance::verifyImage (const tcu::ConstPixelBufferAccess& testSampleMaskImage,
+ const tcu::ConstPixelBufferAccess& minSampleMaskImage,
+ const tcu::ConstPixelBufferAccess& maxSampleMaskImage)
+{
+ const deUint32 testColorCount = getUniqueColorsCount(testSampleMaskImage);
+ const deUint32 minColorCount = getUniqueColorsCount(minSampleMaskImage);
+ const deUint32 maxColorCount = getUniqueColorsCount(maxSampleMaskImage);
+
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+
+ log << tcu::TestLog::Message
+ << "\nColors found: " << testColorCount << "\n"
+ << "Min. colors expected: " << minColorCount << "\n"
+ << "Max. colors expected: " << maxColorCount << "\n"
+ << tcu::TestLog::EndMessage;
+
+ if (minColorCount > testColorCount || testColorCount > maxColorCount)
+ return tcu::TestStatus::fail("Unique colors out of expected bounds");
+ else
+ return tcu::TestStatus::pass("Unique colors within expected bounds");
+}
+
+tcu::TestStatus testRasterSamplesConsistency (Context& context, GeometryType geometryType)
+{
+ // Use triangle only.
+ DE_UNREF(geometryType);
+
+ const VkSampleCountFlagBits samples[] =
+ {
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_SAMPLE_COUNT_2_BIT,
+ VK_SAMPLE_COUNT_4_BIT,
+ VK_SAMPLE_COUNT_8_BIT,
+ VK_SAMPLE_COUNT_16_BIT,
+ VK_SAMPLE_COUNT_32_BIT,
+ VK_SAMPLE_COUNT_64_BIT
+ };
+
+ const Vertex4RGBA vertexData[3] =
+ {
+ {
+ tcu::Vec4(-0.75f, 0.0f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(0.75f, 0.125f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ },
+ {
+ tcu::Vec4(0.75f, -0.125f, 0.0f, 1.0f),
+ tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+ }
+ };
+
+ const std::vector<Vertex4RGBA> vertices (vertexData, vertexData + 3);
+ deUint32 prevUniqueColors = 2;
+ int renderCount = 0;
+
+ // Do not render with 1 sample (start with samplesNdx = 1).
+ for (int samplesNdx = 1; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ if (!isSupportedSampleCount(context.getInstanceInterface(), context.getPhysicalDevice(), samples[samplesNdx]))
+ continue;
+
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ samples[samplesNdx], // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ MultisampleRenderer renderer (context, VK_FORMAT_R8G8B8A8_UNORM, tcu::IVec2(32, 32), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices, multisampleStateParams, getDefaultColorBlendAttachmentState());
+ de::MovePtr<tcu::TextureLevel> result = renderer.render();
+ const deUint32 uniqueColors = getUniqueColorsCount(result->getAccess());
+
+ renderCount++;
+
+ if (prevUniqueColors > uniqueColors)
+ {
+ std::ostringstream message;
+
+ message << "More unique colors generated with " << samples[samplesNdx - 1] << " than with " << samples[samplesNdx];
+ return tcu::TestStatus::fail(message.str());
+ }
+
+ prevUniqueColors = uniqueColors;
+ }
+
+ if (renderCount == 0)
+ throw tcu::NotSupportedError("Multisampling is unsupported");
+
+ return tcu::TestStatus::pass("Number of unique colors increases as the sample count increases");
+}
+
+
+// AlphaToOneInstance
+
+AlphaToOneInstance::AlphaToOneInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState)
+ : vkt::TestInstance (context)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_renderSize (32, 32)
+ , m_primitiveTopology (topology)
+ , m_vertices (vertices)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (blendState)
+{
+ VkPhysicalDeviceFeatures deviceFeatures;
+
+ context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &deviceFeatures);
+
+ if (!deviceFeatures.alphaToOne)
+ throw tcu::NotSupportedError("Alpha-to-one is not supported");
+}
+
+tcu::TestStatus AlphaToOneInstance::iterate (void)
+{
+ DE_ASSERT(m_multisampleStateParams.alphaToOneEnable);
+ DE_ASSERT(m_colorBlendState.blendEnable);
+
+ de::MovePtr<tcu::TextureLevel> alphaOneImage;
+ de::MovePtr<tcu::TextureLevel> noAlphaOneImage;
+
+ // Render with blend enabled and alpha to one on
+ {
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+ alphaOneImage = renderer.render();
+ }
+
+ // Render with blend enabled and alpha to one off
+ {
+ VkPipelineMultisampleStateCreateInfo multisampleParams = m_multisampleStateParams;
+ multisampleParams.alphaToOneEnable = false;
+
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+ noAlphaOneImage = renderer.render();
+ }
+
+ return verifyImage(alphaOneImage->getAccess(), noAlphaOneImage->getAccess());
+}
+
+tcu::TestStatus AlphaToOneInstance::verifyImage (const tcu::ConstPixelBufferAccess& alphaOneImage,
+ const tcu::ConstPixelBufferAccess& noAlphaOneImage)
+{
+ for (int y = 0; y < m_renderSize.y(); y++)
+ {
+ for (int x = 0; x < m_renderSize.x(); x++)
+ {
+ if (!tcu::boolAll(tcu::greaterThanEqual(alphaOneImage.getPixel(x, y), noAlphaOneImage.getPixel(x, y))))
+ {
+ std::ostringstream message;
+ message << "Unsatisfied condition: " << alphaOneImage.getPixel(x, y) << " >= " << noAlphaOneImage.getPixel(x, y);
+ return tcu::TestStatus::fail(message.str());
+ }
+ }
+ }
+
+ return tcu::TestStatus::pass("Image rendered with alpha-to-one contains pixels of image rendered with no alpha-to-one");
+}
+
+
+// AlphaToCoverageInstance
+
+AlphaToCoverageInstance::AlphaToCoverageInstance (Context& context,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState,
+ GeometryType geometryType)
+ : vkt::TestInstance (context)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_renderSize (32, 32)
+ , m_primitiveTopology (topology)
+ , m_vertices (vertices)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (blendState)
+ , m_geometryType (geometryType)
+{
+}
+
+tcu::TestStatus AlphaToCoverageInstance::iterate (void)
+{
+ DE_ASSERT(m_multisampleStateParams.alphaToCoverageEnable);
+
+ de::MovePtr<tcu::TextureLevel> result;
+ MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+
+ result = renderer.render();
+
+ return verifyImage(result->getAccess());
+}
+
+tcu::TestStatus AlphaToCoverageInstance::verifyImage (const tcu::ConstPixelBufferAccess& result)
+{
+ float maxColorValue;
+
+ switch (m_geometryType)
+ {
+ case GEOMETRY_TYPE_OPAQUE_QUAD:
+ maxColorValue = 1.01f;
+ break;
+
+ case GEOMETRY_TYPE_TRANSLUCENT_QUAD:
+ maxColorValue = 0.5f;
+ break;
+
+ case GEOMETRY_TYPE_INVISIBLE_QUAD:
+ maxColorValue = 0.01f;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ for (int y = 0; y < m_renderSize.y(); y++)
+ {
+ for (int x = 0; x < m_renderSize.x(); x++)
+ {
+ if (result.getPixel(x, y).x() > maxColorValue)
+ {
+ std::ostringstream message;
+ message << "Pixel is not below the threshold value (" << result.getPixel(x, y).x() << " > " << maxColorValue << ")";
+ return tcu::TestStatus::fail(message.str());
+ }
+ }
+ }
+
+ return tcu::TestStatus::pass("Image matches reference value");
+}
+
+
+// MultisampleRenderer
+
+MultisampleRenderer::MultisampleRenderer (Context& context,
+ VkFormat colorFormat,
+ const tcu::IVec2& renderSize,
+ VkPrimitiveTopology topology,
+ const std::vector<Vertex4RGBA>& vertices,
+ const VkPipelineMultisampleStateCreateInfo& multisampleStateParams,
+ const VkPipelineColorBlendAttachmentState& blendState)
+
+ : m_context (context)
+ , m_colorFormat (colorFormat)
+ , m_renderSize (renderSize)
+ , m_multisampleStateParams (multisampleStateParams)
+ , m_colorBlendState (blendState)
+{
+ if (!isSupportedSampleCount(context.getInstanceInterface(), context.getPhysicalDevice(), multisampleStateParams.rasterizationSamples))
+ throw tcu::NotSupportedError("Unsupported number of rasterization samples");
+
+ const DeviceInterface& vk = context.getDeviceInterface();
+ const VkDevice vkDevice = context.getDevice();
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+ const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+ // Create color image
+ {
+ const VkImageCreateInfo colorImageParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ m_colorFormat, // VkFormat format;
+ { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arrayLayers;
+ m_multisampleStateParams.rasterizationSamples, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ m_colorImage = createImage(vk, vkDevice, &colorImageParams);
+
+ // Allocate and bind color image memory
+ m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+ VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+ }
+
+ // Create resolve image
+ {
+ const VkImageCreateInfo resolveImageParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ m_colorFormat, // VkFormat format;
+ { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // VkImageUsageFlags usage;
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
+ };
+
+ m_resolveImage = createImage(vk, vkDevice, &resolveImageParams);
+
+ // Allocate and bind resolve image memory
+ m_resolveImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_resolveImage), MemoryRequirement::Any);
+ VK_CHECK(vk.bindImageMemory(vkDevice, *m_resolveImage, m_resolveImageAlloc->getMemory(), m_resolveImageAlloc->getOffset()));
+ }
+
+ // Create color attachment view
+ {
+ const VkImageViewCreateInfo colorAttachmentViewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ *m_colorImage, // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ m_colorFormat, // VkFormat format;
+ componentMappingRGBA, // VkComponentMapping components;
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
+ };
+
+ m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+ }
+
+ // Create resolve attachment view
+ {
+ const VkImageViewCreateInfo resolveAttachmentViewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ *m_resolveImage, // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ m_colorFormat, // VkFormat format;
+ componentMappingRGBA, // VkComponentMapping components;
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
+ };
+
+ m_resolveAttachmentView = createImageView(vk, vkDevice, &resolveAttachmentViewParams);
+ }
+
+ // Create render pass
+ {
+ const VkAttachmentDescription attachmentDescriptions[2] =
+ {
+ {
+ 0u, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ m_multisampleStateParams.rasterizationSamples, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ },
+ {
+ 0u, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ }
+ };
+
+ const VkAttachmentReference colorAttachmentReference =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkAttachmentReference resolveAttachmentReference =
+ {
+ 1u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkSubpassDescription subpassDescription =
+ {
+ 0u, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ 0u, // deUint32 inputAttachmentCount;
+ DE_NULL, // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
+ &resolveAttachmentReference, // const VkAttachmentReference* pResolveAttachments;
+ DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const VkAttachmentReference* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassParams =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkRenderPassCreateFlags flags;
+ 2u, // deUint32 attachmentCount;
+ attachmentDescriptions, // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+ }
+
+ // Create framebuffer
+ {
+ const VkImageView attachments[2] =
+ {
+ *m_colorAttachmentView,
+ *m_resolveAttachmentView
+ };
+
+ const VkFramebufferCreateInfo framebufferParams =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkFramebufferCreateFlags flags;
+ *m_renderPass, // VkRenderPass renderPass;
+ 2u, // deUint32 attachmentCount;
+ attachments, // const VkImageView* pAttachments;
+ (deUint32)m_renderSize.x(), // deUint32 width;
+ (deUint32)m_renderSize.y(), // deUint32 height;
+ 1u // deUint32 layers;
+ };
+
+ m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+ }
+
+ // Create pipeline layout
+ {
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineLayoutCreateFlags flags;
+ 0u, // deUint32 setLayoutCount;
+ DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
+ 0u, // deUint32 pushConstantRangeCount;
+ DE_NULL // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+ }
+
+ m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+ m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+ // Create pipeline
+ {
+ const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+ {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
+ *m_vertexShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
+ *m_fragmentShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ }
+ };
+
+ const VkVertexInputBindingDescription vertexInputBindingDescription =
+ {
+ 0u, // deUint32 binding;
+ sizeof(Vertex4RGBA), // deUint32 stride;
+ VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
+ };
+
+ const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
+ {
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ 0u // deUint32 offset;
+ },
+ {
+ 1u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offset;
+ }
+ };
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineVertexInputStateCreateFlags flags;
+ 1u, // deUint32 vertexBindingDescriptionCount;
+ &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
+ 2u, // deUint32 vertexAttributeDescriptionCount;
+ vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
+ };
+
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
+ topology, // VkPrimitiveTopology topology;
+ false // VkBool32 primitiveRestartEnable;
+ };
+
+ const VkViewport viewport =
+ {
+ 0.0f, // float x;
+ 0.0f, // float y;
+ (float)m_renderSize.x(), // float width;
+ (float)m_renderSize.y(), // float height;
+ 0.0f, // float minDepth;
+ 1.0f // float maxDepth;
+ };
+
+ const VkRect2D scissor =
+ {
+ { 0, 0 }, // VkOffset2D offset;
+ { m_renderSize.x(), m_renderSize.y() } // VkExtent2D extent;
+ };
+
+ const VkPipelineViewportStateCreateInfo viewportStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineViewportStateCreateFlags flags;
+ 1u, // deUint32 viewportCount;
+ &viewport, // const VkViewport* pViewports;
+ 1u, // deUint32 scissorCount;
+ &scissor // const VkRect2D* pScissors;
+ };
+
+ const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineRasterizationStateCreateFlags flags;
+ false, // VkBool32 depthClampEnable;
+ false, // VkBool32 rasterizerDiscardEnable;
+ VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
+ VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FALSE, // VkBool32 depthBiasEnable;
+ 0.0f, // float depthBiasConstantFactor;
+ 0.0f, // float depthBiasClamp;
+ 0.0f, // float depthBiasSlopeFactor;
+ 1.0f // float lineWidth;
+ };
+
+ const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineColorBlendStateCreateFlags flags;
+ false, // VkBool32 logicOpEnable;
+ VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
+ 1u, // deUint32 attachmentCount;
+ &m_colorBlendState, // const VkPipelineColorBlendAttachmentState* pAttachments;
+ { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4];
+ };
+
+ const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDynamicStateCreateFlags flags;
+ 0u, // deUint32 dynamicStateCount;
+ DE_NULL // const VkDynamicState* pDynamicStates;
+ };
+
+ const VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDepthStencilStateCreateFlags flags;
+ false, // VkBool32 depthTestEnable;
+ false, // VkBool32 depthWriteEnable;
+ VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
+ false, // VkBool32 depthBoundsTestEnable;
+ false, // VkBool32 stencilTestEnable;
+ // VkStencilOpState front;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ // VkStencilOpState back;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ -1.0f, // float minDepthBounds;
+ +1.0f, // float maxDepthBounds;
+ };
+
+ const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+ {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineCreateFlags flags;
+ 2u, // deUint32 stageCount;
+ shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages;
+ &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+ &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+ DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
+ &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
+ &m_multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+ &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
+ &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
+ *m_pipelineLayout, // VkPipelineLayout layout;
+ *m_renderPass, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ 0u, // VkPipeline basePipelineHandle;
+ 0u // deInt32 basePipelineIndex;
+ };
+
+ m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+ }
+
+ // Create vertex buffer
+ {
+ const VkBufferCreateInfo vertexBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkBufferCreateFlags flags;
+ 1024u, // VkDeviceSize size;
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
+ m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+ // Load vertices into vertex buffer
+ deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(Vertex4RGBA));
+ flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+ }
+
+ // Create command pool
+ {
+ const VkCommandPoolCreateInfo cmdPoolParams =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
+ queueFamilyIndex, // deUint32 queueFamilyIndex;
+ };
+
+ m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+ }
+
+ // Create command buffer
+ {
+ const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_cmdPool, // VkCommandPool commandPool;
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
+ 1u // deUint32 bufferCount;
+ };
+
+ const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkCommandBufferUsageFlags flags;
+ DE_NULL, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkFramebuffer framebuffer;
+ false, // VkBool32 occlusionQueryEnable;
+ 0u, // VkQueryControlFlags queryFlags;
+ 0u // VkQueryPipelineStatisticFlags pipelineStatistics;
+ };
+
+ VkClearValue colorClearValue;
+ colorClearValue.color.float32[0] = 0.0f;
+ colorClearValue.color.float32[1] = 0.0f;
+ colorClearValue.color.float32[2] = 0.0f;
+ colorClearValue.color.float32[3] = 0.0f;
+
+ const VkClearValue clearValues[2] =
+ {
+ colorClearValue,
+ colorClearValue
+ };
+
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_renderPass, // VkRenderPass renderPass;
+ *m_framebuffer, // VkFramebuffer framebuffer;
+ { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea;
+ 2, // deUint32 clearValueCount;
+ clearValues // const VkClearValue* pClearValues;
+ };
+
+ m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+ VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+ vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ VkDeviceSize vertexBufferOffset = 0u;
+
+ vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+ vk.cmdDraw(*m_cmdBuffer, (deUint32)vertices.size(), 1, 0, 0);
+
+ vk.cmdEndRenderPass(*m_cmdBuffer);
+
+ VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+ }
+
+ // Create fence
+ {
+ const VkFenceCreateInfo fenceParams =
+ {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u // VkFenceCreateFlags flags;
+ };
+
+ m_fence = createFence(vk, vkDevice, &fenceParams);
+ }
+}
+
+MultisampleRenderer::~MultisampleRenderer (void)
+{
+}
+
+de::MovePtr<tcu::TextureLevel> MultisampleRenderer::render (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // deUint32 waitSemaphoreCount;
+ DE_NULL, // const VkSemaphore* pWaitSemaphores;
+ 1u, // deUint32 commandBufferCount;
+ &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
+ 0u, // deUint32 signalSemaphoreCount;
+ DE_NULL // const VkSemaphore* pSignalSemaphores;
+ };
+
+ VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+ VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+ VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+ return readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_resolveImage, m_colorFormat, m_renderSize);
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createMultisampleTests (tcu::TestContext& testCtx)
+{
+ const VkSampleCountFlagBits samples[] =
+ {
+ VK_SAMPLE_COUNT_2_BIT,
+ VK_SAMPLE_COUNT_4_BIT,
+ VK_SAMPLE_COUNT_8_BIT,
+ VK_SAMPLE_COUNT_16_BIT,
+ VK_SAMPLE_COUNT_32_BIT,
+ VK_SAMPLE_COUNT_64_BIT
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> multisampleTests (new tcu::TestCaseGroup(testCtx, "multisample", ""));
+
+ // Rasterization samples tests
+ {
+ de::MovePtr<tcu::TestCaseGroup> rasterizationSamplesTests(new tcu::TestCaseGroup(testCtx, "raster_samples", ""));
+
+ for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ std::ostringstream caseName;
+ caseName << "samples_" << samples[samplesNdx];
+
+ de::MovePtr<tcu::TestCaseGroup> samplesTests (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+ samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_triangle", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+ samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_line", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_LINE));
+ samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_point", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_POINT));
+
+ rasterizationSamplesTests->addChild(samplesTests.release());
+ }
+
+ multisampleTests->addChild(rasterizationSamplesTests.release());
+ }
+
+ // Raster samples consistency check
+ {
+ de::MovePtr<tcu::TestCaseGroup> rasterSamplesConsistencyTests(new tcu::TestCaseGroup(testCtx, "raster_samples_consistency", ""));
+
+ addFunctionCaseWithPrograms(rasterSamplesConsistencyTests.get(),
+ "unique_colors_check",
+ "",
+ initMultisamplePrograms,
+ testRasterSamplesConsistency,
+ GEOMETRY_TYPE_OPAQUE_TRIANGLE);
+
+ multisampleTests->addChild(rasterSamplesConsistencyTests.release());
+ }
+
+ // minSampleShading tests
+ {
+ struct TestConfig
+ {
+ const char* name;
+ float minSampleShading;
+ };
+
+ const TestConfig testConfigs[] =
+ {
+ { "min_0_0", 0.0f },
+ { "min_0_25", 0.25f },
+ { "min_0_5", 0.5f },
+ { "min_0_75", 0.75f },
+ { "min_1_0", 1.0f }
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> minSampleShadingTests(new tcu::TestCaseGroup(testCtx, "min_sample_shading", ""));
+
+ for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(testConfigs); configNdx++)
+ {
+ const TestConfig& testConfig = testConfigs[configNdx];
+ de::MovePtr<tcu::TestCaseGroup> minShadingValueTests (new tcu::TestCaseGroup(testCtx, testConfigs[configNdx].name, ""));
+
+ for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ std::ostringstream caseName;
+ caseName << "samples_" << samples[samplesNdx];
+
+ de::MovePtr<tcu::TestCaseGroup> samplesTests (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+ samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_triangle", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+ samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_line", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_LINE));
+ samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_point", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_POINT));
+
+ minShadingValueTests->addChild(samplesTests.release());
+ }
+
+ minSampleShadingTests->addChild(minShadingValueTests.release());
+ }
+
+ multisampleTests->addChild(minSampleShadingTests.release());
+ }
+
+ // pSampleMask tests
+ {
+ struct TestConfig
+ {
+ const char* name;
+ const char* description;
+ VkSampleMask sampleMask;
+ };
+
+ const TestConfig testConfigs[] =
+ {
+ { "mask_all_on", "All mask bits are off", 0x0 },
+ { "mask_all_off", "All mask bits are on", 0xFFFFFFFF },
+ { "mask_one", "All mask elements are 0x1", 0x1},
+ { "mask_random", "All mask elements are 0xAAAAAAAA", 0xAAAAAAAA },
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> sampleMaskTests(new tcu::TestCaseGroup(testCtx, "sample_mask", ""));
+
+ for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(testConfigs); configNdx++)
+ {
+ const TestConfig& testConfig = testConfigs[configNdx];
+ de::MovePtr<tcu::TestCaseGroup> sampleMaskValueTests (new tcu::TestCaseGroup(testCtx, testConfig.name, testConfig.description));
+
+ for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ std::ostringstream caseName;
+ caseName << "samples_" << samples[samplesNdx];
+
+ const deUint32 sampleMaskCount = samples[samplesNdx] / 32;
+ de::MovePtr<tcu::TestCaseGroup> samplesTests (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+ std::vector<VkSampleMask> mask;
+ for (deUint32 maskNdx = 0; maskNdx < sampleMaskCount; maskNdx++)
+ mask.push_back(testConfig.sampleMask);
+
+ samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_triangle", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+ samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_line", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_LINE));
+ samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_point", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_POINT));
+
+ sampleMaskValueTests->addChild(samplesTests.release());
+ }
+
+ sampleMaskTests->addChild(sampleMaskValueTests.release());
+ }
+
+ multisampleTests->addChild(sampleMaskTests.release());
+
+ }
+
+ // AlphaToOne tests
+ {
+ de::MovePtr<tcu::TestCaseGroup> alphaToOneTests(new tcu::TestCaseGroup(testCtx, "alpha_to_one", ""));
+
+ for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ std::ostringstream caseName;
+ caseName << "samples_" << samples[samplesNdx];
+
+ alphaToOneTests->addChild(new AlphaToOneTest(testCtx, caseName.str(), "", samples[samplesNdx]));
+ }
+
+ multisampleTests->addChild(alphaToOneTests.release());
+ }
+
+ // AlphaToCoverageEnable tests
+ {
+ de::MovePtr<tcu::TestCaseGroup> alphaToCoverageTests (new tcu::TestCaseGroup(testCtx, "alpha_to_coverage", ""));
+
+ for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+ {
+ std::ostringstream caseName;
+ caseName << "samples_" << samples[samplesNdx];
+
+ de::MovePtr<tcu::TestCaseGroup> samplesTests (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+ samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_opaque", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_QUAD));
+ samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_translucent", "", samples[samplesNdx], GEOMETRY_TYPE_TRANSLUCENT_QUAD));
+ samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_invisible", "", samples[samplesNdx], GEOMETRY_TYPE_INVISIBLE_QUAD));
+
+ alphaToCoverageTests->addChild(samplesTests.release());
+ }
+ multisampleTests->addChild(alphaToCoverageTests.release());
+ }
+
+ return multisampleTests.release();
+}
+
+} // pipeline
+} // vkt
--- /dev/null
+#ifndef _VKTPIPELINEMULTISAMPLETESTS_HPP
+#define _VKTPIPELINEMULTISAMPLETESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Multisample Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createMultisampleTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEMULTISAMPLETESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 ARM Limited.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief PushConstant Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelinePushConstantTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deMemory.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+enum
+{
+ TRIANGLE_COUNT = 2,
+ MAX_RANGE_COUNT = 5
+};
+
+enum RangeSizeCase
+{
+ SIZE_CASE_4 = 0,
+ SIZE_CASE_16,
+ SIZE_CASE_40,
+ SIZE_CASE_128,
+ SIZE_CASE_UNSUPPORTED
+};
+
+struct PushConstantData
+{
+ struct PushConstantRange
+ {
+ VkShaderStageFlags shaderStage;
+ deUint32 offset;
+ deUint32 size;
+ } range;
+ struct PushConstantUpdate
+ {
+ deUint32 offset;
+ deUint32 size;
+ } update;
+};
+
+class PushConstantGraphicsTest : public vkt::TestCase
+{
+public:
+ PushConstantGraphicsTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const deUint32 rangeCount,
+ const PushConstantData pushConstantRange[MAX_RANGE_COUNT],
+ const deBool multipleUpdate);
+ virtual ~PushConstantGraphicsTest (void);
+ virtual void initPrograms (SourceCollections& sourceCollections) const;
+ virtual TestInstance* createInstance (Context& context) const;
+ RangeSizeCase getRangeSizeCase (deUint32 rangeSize) const;
+
+private:
+ const deUint32 m_rangeCount;
+ PushConstantData m_pushConstantRange[MAX_RANGE_COUNT];
+ const deBool m_multipleUpdate;
+};
+
+class PushConstantGraphicsTestInstance : public vkt::TestInstance
+{
+public:
+ PushConstantGraphicsTestInstance (Context& context,
+ const deUint32 rangeCount,
+ const PushConstantData pushConstantRange[MAX_RANGE_COUNT],
+ const deBool multipleUpdate);
+ virtual ~PushConstantGraphicsTestInstance (void);
+ virtual tcu::TestStatus iterate (void);
+
+ void createShaderStage (const DeviceInterface& vk,
+ VkDevice device,
+ const BinaryCollection& programCollection,
+ const char* name,
+ VkShaderStageFlagBits stage,
+ Move<VkShaderModule>* module);
+ std::vector<Vertex4RGBA> createQuad (const float size);
+
+private:
+ tcu::TestStatus verifyImage (void);
+
+private:
+ const tcu::IVec2 m_renderSize;
+ const VkFormat m_colorFormat;
+ const deUint32 m_rangeCount;
+ PushConstantData m_pushConstantRange[MAX_RANGE_COUNT];
+ const deBool m_multipleUpdate;
+
+ VkImageCreateInfo m_colorImageCreateInfo;
+ Move<VkImage> m_colorImage;
+ de::MovePtr<Allocation> m_colorImageAlloc;
+ Move<VkImageView> m_colorAttachmentView;
+ Move<VkRenderPass> m_renderPass;
+ Move<VkFramebuffer> m_framebuffer;
+
+ Move<VkShaderModule> m_vertexShaderModule;
+ Move<VkShaderModule> m_fragmentShaderModule;
+ Move<VkShaderModule> m_geometryShaderModule;
+ Move<VkShaderModule> m_tessControlShaderModule;
+ Move<VkShaderModule> m_tessEvaluationShaderModule;
+
+ VkShaderStageFlags m_shaderFlags;
+ std::vector<VkPipelineShaderStageCreateInfo> m_shaderStage;
+
+ Move<VkBuffer> m_vertexBuffer;
+ std::vector<Vertex4RGBA> m_vertices;
+ de::MovePtr<Allocation> m_vertexBufferAlloc;
+
+ Move<VkBuffer> m_uniformBuffer;
+ de::MovePtr<Allocation> m_uniformBufferAlloc;
+ Move<VkDescriptorPool> m_descriptorPool;
+ Move<VkDescriptorSetLayout> m_descriptorSetLayout;
+ Move<VkDescriptorSet> m_descriptorSet;
+
+ Move<VkPipelineLayout> m_pipelineLayout;
+ Move<VkPipeline> m_graphicsPipelines;
+
+ Move<VkCommandPool> m_cmdPool;
+ Move<VkCommandBuffer> m_cmdBuffer;
+
+ Move<VkFence> m_fence;
+};
+
+PushConstantGraphicsTest::PushConstantGraphicsTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const deUint32 rangeCount,
+ const PushConstantData pushConstantRange[MAX_RANGE_COUNT],
+ const deBool multipleUpdate)
+ : vkt::TestCase (testContext, name, description)
+ , m_rangeCount (rangeCount)
+ , m_multipleUpdate (multipleUpdate)
+{
+ deMemcpy(m_pushConstantRange, pushConstantRange, sizeof(PushConstantData) * MAX_RANGE_COUNT);
+}
+
+PushConstantGraphicsTest::~PushConstantGraphicsTest (void)
+{
+}
+
+TestInstance* PushConstantGraphicsTest::createInstance (Context& context) const
+{
+ return new PushConstantGraphicsTestInstance(context, m_rangeCount, m_pushConstantRange, m_multipleUpdate);
+}
+
+RangeSizeCase PushConstantGraphicsTest::getRangeSizeCase (deUint32 rangeSize) const
+{
+ switch (rangeSize)
+ {
+ case 4:
+ return SIZE_CASE_4;
+ case 16:
+ return SIZE_CASE_16;
+ case 40:
+ return SIZE_CASE_40;
+ case 128:
+ return SIZE_CASE_128;
+ default:
+ DE_FATAL("Range size unsupported yet");
+ return SIZE_CASE_UNSUPPORTED;
+ }
+}
+
+void PushConstantGraphicsTest::initPrograms (SourceCollections& sourceCollections) const
+{
+ std::ostringstream vertexSrc;
+ std::ostringstream fragmentSrc;
+ std::ostringstream geometrySrc;
+ std::ostringstream tessControlSrc;
+ std::ostringstream tessEvaluationSrc;
+
+ for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+ {
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_VERTEX_BIT)
+ {
+ vertexSrc << "#version 450\n"
+ << "layout(location = 0) in highp vec4 position;\n"
+ << "layout(location = 1) in highp vec4 color;\n"
+ << "layout(location = 0) out highp vec4 vtxColor;\n"
+ << "layout(push_constant) uniform Material {\n";
+
+ switch (getRangeSizeCase(m_pushConstantRange[rangeNdx].range.size))
+ {
+ case SIZE_CASE_4:
+ vertexSrc << "int kind;\n"
+ << "} matInst;\n";
+ break;
+ case SIZE_CASE_16:
+ vertexSrc << "vec4 color;\n"
+ << "} matInst;\n"
+ << "layout(location = 0) uniform UniformBuf {\n"
+ << "vec4 element;\n"
+ << "} uniformBuf;\n";
+ break;
+ case SIZE_CASE_40:
+ vertexSrc << "int kind;\n"
+ << "vec4 color;\n"
+ << "} matInst[2];\n";
+ break;
+ case SIZE_CASE_128:
+ vertexSrc << "vec4 color[8];\n"
+ << "} matInst;\n";
+ break;
+ default:
+ DE_FATAL("Not implemented yet");
+ break;
+ }
+
+ vertexSrc << "void main()\n"
+ << "{\n"
+ << " gl_Position = position;\n";
+
+ switch (getRangeSizeCase(m_pushConstantRange[rangeNdx].range.size))
+ {
+ case SIZE_CASE_4:
+ vertexSrc << "switch (matInst.kind) {\n"
+ << "case 0: vtxColor = vec4(0.0, 1.0, 0, 1.0); break;\n"
+ << "case 1: vtxColor = vec4(0.0, 0.0, 1.0, 1.0); break;\n"
+ << "case 2: vtxColor = vec4(1.0, 0.0, 0, 1.0); break;\n"
+ << "default: vtxColor = color; break;}\n"
+ << "}\n";
+ break;
+ case SIZE_CASE_16:
+ vertexSrc << "vtxColor = (matInst.color + uniformBuf.element) * 0.5;\n"
+ << "}\n";
+ break;
+ case SIZE_CASE_40:
+ vertexSrc << "vtxColor = matInst[1].color;\n"
+ << "}\n";
+ break;
+ case SIZE_CASE_128:
+ vertexSrc << "vec4 color = vec4(0.0, 0, 0, 0.0);\n"
+ << "for (int i = 0; i < 8; i++)\n"
+ << "{\n"
+ << " color = color + matInst.color[i];\n"
+ << "}\n"
+ << "vtxColor = color * 0.125;\n"
+ << "}\n";
+ break;
+ default:
+ DE_FATAL("Not implemented yet");
+ break;
+ }
+
+ sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSrc.str());
+ }
+
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+ {
+ tessControlSrc << "#version 450\n"
+ << "layout (vertices = 3) out;\n"
+ << "layout(push_constant) uniform TessLevel {\n"
+ << " layout(offset = 24) int level;\n"
+ << "} tessLevel;\n"
+ << "in highp vec4 color[];\n"
+ << "out highp vec4 vtxColor[];\n"
+ << "void main()\n"
+ << "{\n"
+ << " gl_TessLevelInner[0] = tessLevel.level;\n"
+ << " gl_TessLevelOuter[0] = tessLevel.level;\n"
+ << " gl_TessLevelOuter[1] = tessLevel.level;\n"
+ << " gl_TessLevelOuter[2] = tessLevel.level;\n"
+ << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+ << " vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("color_tesc") << glu::TessellationControlSource(tessControlSrc.str());
+ }
+
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+ {
+ tessEvaluationSrc << "#version 450\n"
+ << "layout (triangles) in;\n"
+ << "layout(push_constant) uniform Material {\n"
+ << " layout(offset = 28) vec4 color;\n"
+ << "} matInst;\n"
+ << "in highp vec4 color[];\n"
+ << "out highp vec4 vtxColor;\n"
+ << "void main()\n"
+ << "{\n"
+ << " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
+ << " vtxColor = matInst.color;\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("color_tese") << glu::TessellationEvaluationSource(tessEvaluationSrc.str());
+ }
+
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_GEOMETRY_BIT)
+ {
+ geometrySrc << "#version 450\n"
+ << "layout(triangles) in;\n"
+ << "layout(triangle_strip, max_vertices=3) out;\n"
+ << "layout(push_constant) uniform Material {\n"
+ << " layout(offset = 20) int kind;\n"
+ << "} matInst;\n"
+ << "in highp vec4 color[];\n"
+ << "out highp vec4 vtxColor;\n"
+ << "void main()\n"
+ << "{\n"
+ << " for(int i=0; i<3; i++)\n"
+ << " {\n"
+ << " gl_Position.xyz = gl_in[i].gl_Position.xyz / matInst.kind;\n"
+ << " gl_Position.w = gl_in[i].gl_Position.w;\n"
+ << " vtxColor = color[i];\n"
+ << " EmitVertex();\n"
+ << " }\n"
+ << " EndPrimitive();\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("color_geom") << glu::GeometrySource(geometrySrc.str());
+ }
+
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT)
+ {
+ fragmentSrc << "#version 450\n"
+ << "layout(location = 0) in highp vec4 vtxColor;\n"
+ << "layout(location = 0) out highp vec4 fragColor;\n"
+ << "layout(push_constant) uniform Material {\n";
+
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_VERTEX_BIT)
+ {
+ fragmentSrc << " layout(offset = 0) int kind;\n"
+ << "} matInst;\n";
+ }
+ else
+ {
+ fragmentSrc << " layout(offset = 16) int kind;\n"
+ << "} matInst;\n";
+ }
+
+ fragmentSrc << "void main (void)\n"
+ << "{\n"
+ << " switch (matInst.kind) {\n"
+ << " case 0: fragColor = vec4(0, 1.0, 0, 1.0); break;\n"
+ << " case 1: fragColor = vec4(0, 0.0, 1.0, 1.0); break;\n"
+ << " case 2: fragColor = vtxColor; break;\n"
+ << " default: fragColor = vec4(1.0, 1.0, 1.0, 1.0); break;}\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSrc.str());
+ }
+ }
+
+ // add a pass through fragment shader if it's not activated in push constant ranges
+ if (fragmentSrc.str().empty())
+ {
+ fragmentSrc << "#version 450\n"
+ << "layout(location = 0) in highp vec4 vtxColor;\n"
+ << "layout(location = 0) out highp vec4 fragColor;\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " fragColor = vtxColor;\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSrc.str());
+ }
+}
+
+void PushConstantGraphicsTestInstance::createShaderStage (const DeviceInterface& vk,
+ VkDevice device,
+ const BinaryCollection& programCollection,
+ const char* name,
+ VkShaderStageFlagBits stage,
+ Move<VkShaderModule>* module)
+{
+ *module = createShaderModule(vk, device, programCollection.get(name), 0);
+
+ const vk::VkPipelineShaderStageCreateInfo stageCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ stage, // VkShaderStageFlagBits stage;
+ **module, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ };
+
+ m_shaderStage.push_back(stageCreateInfo);
+}
+
+std::vector<Vertex4RGBA> PushConstantGraphicsTestInstance::createQuad(const float size)
+{
+ std::vector<Vertex4RGBA> vertices;
+
+ const tcu::Vec4 color = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+ const Vertex4RGBA lowerLeftVertex = {tcu::Vec4(-size, -size, 0.0f, 1.0f), color};
+ const Vertex4RGBA lowerRightVertex = {tcu::Vec4(size, -size, 0.0f, 1.0f), color};
+ const Vertex4RGBA UpperLeftVertex = {tcu::Vec4(-size, size, 0.0f, 1.0f), color};
+ const Vertex4RGBA UpperRightVertex = {tcu::Vec4(size, size, 0.0f, 1.0f), color};
+
+ vertices.push_back(lowerLeftVertex);
+ vertices.push_back(lowerRightVertex);
+ vertices.push_back(UpperLeftVertex);
+ vertices.push_back(UpperLeftVertex);
+ vertices.push_back(lowerRightVertex);
+ vertices.push_back(UpperRightVertex);
+
+ return vertices;
+}
+
+PushConstantGraphicsTestInstance::PushConstantGraphicsTestInstance (Context& context,
+ const deUint32 rangeCount,
+ const PushConstantData pushConstantRange[MAX_RANGE_COUNT],
+ deBool multipleUpdate)
+ : vkt::TestInstance (context)
+ , m_renderSize (32, 32)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+ , m_rangeCount (rangeCount)
+ , m_multipleUpdate (multipleUpdate)
+ , m_shaderFlags (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
+{
+ const DeviceInterface& vk = context.getDeviceInterface();
+ const VkDevice vkDevice = context.getDevice();
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+ const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+ deMemcpy(m_pushConstantRange, pushConstantRange, sizeof(PushConstantData) * MAX_RANGE_COUNT);
+
+ // Create color image
+ {
+ const VkImageCreateInfo colorImageParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ m_colorFormat, // VkFormat format;
+ { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ m_colorImageCreateInfo = colorImageParams;
+ m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+ // Allocate and bind color image memory
+ m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+ VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+ }
+
+ // Create color attachment view
+ {
+ const VkImageViewCreateInfo colorAttachmentViewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ *m_colorImage, // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ m_colorFormat, // VkFormat format;
+ componentMappingRGBA, // VkChannelMapping channels;
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange;
+ };
+
+ m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+ }
+
+ // Create render pass
+ {
+ const VkAttachmentDescription colorAttachmentDescription =
+ {
+ 0u, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentDescription attachments[1] =
+ {
+ colorAttachmentDescription
+ };
+
+ const VkAttachmentReference colorAttachmentReference =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkAttachmentReference depthAttachmentReference =
+ {
+ VK_ATTACHMENT_UNUSED, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout;
+ };
+
+ const VkSubpassDescription subpassDescription =
+ {
+ 0u, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ 0u, // deUint32 inputAttachmentCount;
+ DE_NULL, // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
+ DE_NULL, // const VkAttachmentReference* pResolveAttachments;
+ &depthAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const VkAttachmentReference* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassParams =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkRenderPassCreateFlags flags;
+ 1u, // deUint32 attachmentCount;
+ attachments, // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+ }
+
+ // Create framebuffer
+ {
+ const VkImageView attachmentBindInfos[1] =
+ {
+ *m_colorAttachmentView
+ };
+
+ const VkFramebufferCreateInfo framebufferParams =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkFramebufferCreateFlags flags;
+ *m_renderPass, // VkRenderPass renderPass;
+ 1u, // deUint32 attachmentCount;
+ attachmentBindInfos, // const VkImageView* pAttachments;
+ (deUint32)m_renderSize.x(), // deUint32 width;
+ (deUint32)m_renderSize.y(), // deUint32 height;
+ 1u // deUint32 layers;
+ };
+
+ m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+ }
+
+ // Create pipeline layout
+ {
+ // create push constant range
+ VkPushConstantRange pushConstantRanges[MAX_RANGE_COUNT];
+ for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+ {
+ pushConstantRanges[rangeNdx].stageFlags = m_pushConstantRange[rangeNdx].range.shaderStage;
+ pushConstantRanges[rangeNdx].offset = m_pushConstantRange[rangeNdx].range.offset;
+ pushConstantRanges[rangeNdx].size = m_pushConstantRange[rangeNdx].range.size;
+ }
+
+ // create descriptor set layout
+ m_descriptorSetLayout = DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT).build(vk, vkDevice);
+
+ // create descriptor pool
+ m_descriptorPool = DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u).build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+
+ // create uniform buffer
+ const VkBufferCreateInfo uniformBufferCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 16u, // VkDeviceSize size;
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
+ 0u, // VkBufferCreateFlags flags;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ m_uniformBuffer = createBuffer(vk, vkDevice, &uniformBufferCreateInfo);
+ m_uniformBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_uniformBuffer), MemoryRequirement::HostVisible);
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferAlloc->getMemory(), m_uniformBufferAlloc->getOffset()));
+
+ tcu::Vec4 value = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+ deMemcpy(m_uniformBufferAlloc->getHostPtr(), &value, 16u);
+ flushMappedMemoryRange(vk, vkDevice, m_uniformBufferAlloc->getMemory(), m_uniformBufferAlloc->getOffset(), 16u);
+
+ // create and update descriptor set
+ const VkDescriptorSetAllocateInfo allocInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_descriptorPool, // VkDescriptorPool descriptorPool;
+ 1u, // uint32_t setLayoutCount;
+ &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
+ };
+ m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+
+ const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*m_uniformBuffer, (VkDeviceSize)0u, (VkDeviceSize)16u);
+
+ DescriptorSetUpdateBuilder()
+ .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorInfo)
+ .update(vk, vkDevice);
+
+ // create pipeline layout
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineLayoutCreateFlags flags;
+ 1u, // deUint32 descriptorSetCount;
+ &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
+ m_rangeCount, // deUint32 pushConstantRangeCount;
+ pushConstantRanges // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+ }
+
+ // Create shaders
+ {
+ for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+ {
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_GEOMETRY_BIT)
+ {
+ m_shaderFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
+ }
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+ {
+ m_shaderFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+ }
+ if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+ {
+ m_shaderFlags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+ }
+ }
+
+ VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
+
+ createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_vert", VK_SHADER_STAGE_VERTEX_BIT , &m_vertexShaderModule);
+ if (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+ {
+ if (features.tessellationShader == VK_FALSE)
+ {
+ TCU_THROW(NotSupportedError, "Tessellation Not Supported");
+ }
+ createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_tesc", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, &m_tessControlShaderModule);
+ createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_tese", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, &m_tessEvaluationShaderModule);
+ }
+ if (m_shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
+ {
+ if (features.geometryShader == VK_FALSE)
+ {
+ TCU_THROW(NotSupportedError, "Geometry Not Supported");
+ }
+ createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_geom", VK_SHADER_STAGE_GEOMETRY_BIT, &m_geometryShaderModule);
+ }
+ createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_frag", VK_SHADER_STAGE_FRAGMENT_BIT, &m_fragmentShaderModule);
+ }
+
+ // Create pipeline
+ {
+ const VkVertexInputBindingDescription vertexInputBindingDescription =
+ {
+ 0u, // deUint32 binding;
+ sizeof(Vertex4RGBA), // deUint32 strideInBytes;
+ VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
+ };
+
+ const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
+ {
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ 0u // deUint32 offsetInBytes;
+ }
+ };
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // vkPipelineVertexInputStateCreateFlags flags;
+ 1u, // deUint32 bindingCount;
+ &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
+ 1u, // deUint32 attributeCount;
+ vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
+ };
+
+ const VkPrimitiveTopology topology = (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineInputAssemblyStateCreateFlags)0u, // VkPipelineInputAssemblyStateCreateFlags flags;
+ topology, // VkPrimitiveTopology topology;
+ false // VkBool32 primitiveRestartEnable;
+ };
+
+ const VkViewport viewport =
+ {
+ 0.0f, // float originX;
+ 0.0f, // float originY;
+ (float)m_renderSize.x(), // float width;
+ (float)m_renderSize.y(), // float height;
+ 0.0f, // float minDepth;
+ 1.0f // float maxDepth;
+ };
+
+ const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+ const VkPipelineViewportStateCreateInfo viewportStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineViewportStateCreateFlags)0u, // VkPipelineViewportStateCreateFlags flags;
+ 1u, // deUint32 viewportCount;
+ &viewport, // const VkViewport* pViewports;
+ 1u, // deUint32 scissorCount;
+ &scissor, // const VkRect2D* pScissors;
+ };
+
+ const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineRasterizationStateCreateFlags flags;
+ false, // VkBool32 depthClampEnable;
+ false, // VkBool32 rasterizerDiscardEnable;
+ VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
+ VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FALSE, // VkBool32 depthBiasEnable;
+ 0.0f, // float depthBiasConstantFactor;
+ 0.0f, // float depthBiasClamp;
+ 0.0f, // float depthBiasSlopeFactor;
+ 1.0f, // float lineWidth;
+ };
+
+ const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+ {
+ false, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+ };
+
+ const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0, // VkPipelineColorBlendStateCreateFlags flags;
+ false, // VkBool32 logicOpEnable;
+ VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
+ 1u, // deUint32 attachmentCount;
+ &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
+ { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
+ };
+
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDynamicStateCreateFlags flags;
+ 0u, // deUint32 dynamicStateCount;
+ DE_NULL // const VkDynamicState* pDynamicStates;
+ };
+
+ VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDepthStencilStateCreateFlags flags;
+ false, // VkBool32 depthTestEnable;
+ false, // VkBool32 depthWriteEnable;
+ VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
+ false, // VkBool32 depthBoundsTestEnable;
+ false, // VkBool32 stencilTestEnable;
+ // VkStencilOpState front;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilFailOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilPassOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilDepthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp stencilCompareOp;
+ 0u, // deUint32 stencilCompareMask;
+ 0u, // deUint32 stencilWriteMask;
+ 0u, // deUint32 stencilReference;
+ },
+ // VkStencilOpState back;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilFailOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilPassOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp stencilDepthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp stencilCompareOp;
+ 0u, // deUint32 stencilCompareMask;
+ 0u, // deUint32 stencilWriteMask;
+ 0u, // deUint32 stencilReference;
+ },
+ -1.0f, // float minDepthBounds;
+ +1.0f, // float maxDepthBounds;
+ };
+
+ const VkPipelineTessellationStateCreateInfo tessellationStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineTesselationStateCreateFlags flags;
+ 3u, // uint32_t patchControlPoints;
+ };
+
+ const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+ {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineCreateFlags flags;
+ (deUint32)m_shaderStage.size(), // deUint32 stageCount;
+ &m_shaderStage[0], // const VkPipelineShaderStageCreateInfo* pStages;
+ &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+ &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+ (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? &tessellationStateParams: DE_NULL), // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
+ &rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+ &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
+ &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
+ *m_pipelineLayout, // VkPipelineLayout layout;
+ *m_renderPass, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ 0u, // VkPipeline basePipelineHandle;
+ 0u // deInt32 basePipelineIndex;
+ };
+
+ m_graphicsPipelines = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+ }
+
+ // Create vertex buffer
+ {
+ m_vertices = createQuad(1.0f);
+
+ const VkBufferCreateInfo vertexBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkBufferCreateFlags flags;
+ (VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()), // VkDeviceSize size;
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
+ m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+ // Load vertices into vertex buffer
+ deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+ flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+ }
+
+ // Create command pool
+ {
+ const VkCommandPoolCreateInfo cmdPoolParams =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags;
+ queueFamilyIndex // deUint32 queueFamilyIndex;
+ };
+ m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+ }
+
+ // Create command buffer
+ {
+ const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_cmdPool, // VkCommandPool commandPool;
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
+ 1u // deUint32 bufferCount;
+ };
+
+ const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkCommandBufferUsageFlags flags;
+ DE_NULL, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkFramebuffer framebuffer;
+ false, // VkBool32 occlusionQueryEnable;
+ 0u, // VkQueryControlFlags queryFlags;
+ 0u // VkQueryPipelineStatisticFlags pipelineStatistics;
+ };
+
+ const VkClearValue attachmentClearValues[] =
+ {
+ defaultClearValue(m_colorFormat)
+ };
+
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_renderPass, // VkRenderPass renderPass;
+ *m_framebuffer, // VkFramebuffer framebuffer;
+ { { 0, 0 } , { m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea;
+ 1, // deUint32 clearValueCount;
+ attachmentClearValues // const VkClearValue* pClearValues;
+ };
+
+ m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+ VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+ vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ // update push constant
+ std::vector<tcu::Vec4> color(8, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+ std::vector<tcu::Vec4> allOnes(8, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+
+ const deUint32 kind = 2u;
+ const void* value = DE_NULL;
+ for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+ {
+ value = (m_pushConstantRange[rangeNdx].range.size == 4u) ? (void*)(&kind) : (void*)(&color[0]);
+
+ vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[rangeNdx].range.shaderStage, m_pushConstantRange[rangeNdx].range.offset, m_pushConstantRange[rangeNdx].range.size, value);
+
+ if (m_pushConstantRange[rangeNdx].update.size < m_pushConstantRange[rangeNdx].range.size)
+ {
+ value = (void*)(&allOnes[0]);
+ vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[rangeNdx].range.shaderStage, m_pushConstantRange[rangeNdx].update.offset, m_pushConstantRange[rangeNdx].update.size, value);
+ }
+ }
+
+ // draw quad
+ const VkDeviceSize triangleOffset = (m_vertices.size() / TRIANGLE_COUNT) * sizeof(Vertex4RGBA);
+ for (int triangleNdx = 0; triangleNdx < TRIANGLE_COUNT; triangleNdx++)
+ {
+ VkDeviceSize vertexBufferOffset = triangleOffset * triangleNdx;
+
+ if (m_multipleUpdate)
+ {
+ vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[0].range.shaderStage, m_pushConstantRange[0].range.offset, m_pushConstantRange[0].range.size, &triangleNdx);
+ }
+
+ vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines);
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+ vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &(*m_descriptorSet), 0, DE_NULL);
+
+ vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / TRIANGLE_COUNT), 1, 0, 0);
+ }
+
+ vk.cmdEndRenderPass(*m_cmdBuffer);
+ VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+ }
+
+ // Create fence
+ {
+ const VkFenceCreateInfo fenceParams =
+ {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u // VkFenceCreateFlags flags;
+ };
+
+ m_fence = createFence(vk, vkDevice, &fenceParams);
+ }
+}
+
+PushConstantGraphicsTestInstance::~PushConstantGraphicsTestInstance (void)
+{
+}
+
+tcu::TestStatus PushConstantGraphicsTestInstance::iterate (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // deUint32 waitSemaphoreCount;
+ DE_NULL, // const VkSemaphore* pWaitSemaphores;
+ 1u, // deUint32 commandBufferCount;
+ &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
+ 0u, // deUint32 signalSemaphoreCount;
+ DE_NULL // const VkSemaphore* pSignalSemaphores;
+ };
+
+ VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+ VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+ VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+ return verifyImage();
+}
+
+tcu::TestStatus PushConstantGraphicsTestInstance::verifyImage (void)
+{
+ const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
+ const tcu::TextureFormat tcuDepthFormat = tcu::TextureFormat();
+ const ColorVertexShader vertexShader;
+ const ColorFragmentShader fragmentShader (tcuColorFormat, tcuDepthFormat);
+ const rr::Program program (&vertexShader, &fragmentShader);
+ ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+ bool compareOk = false;
+
+ // Render reference image
+ {
+ if (m_shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
+ {
+ m_vertices = createQuad(0.5f);
+ }
+
+ for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+ {
+ if (m_pushConstantRange[rangeNdx].update.size < m_pushConstantRange[rangeNdx].range.size)
+ {
+ for (size_t vertexNdx = 0; vertexNdx < m_vertices.size(); vertexNdx++)
+ {
+ m_vertices[vertexNdx].color.xyzw() = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ }
+ }
+
+ if (m_multipleUpdate)
+ {
+ for (size_t vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+ {
+ m_vertices[vertexNdx].color.xyz() = tcu::Vec3(0.0f, 1.0f, 0.0f);
+ }
+ for (size_t vertexNdx = 3; vertexNdx < m_vertices.size(); vertexNdx++)
+ {
+ m_vertices[vertexNdx].color.xyz() = tcu::Vec3(0.0f, 0.0f, 1.0f);
+ }
+ }
+
+ for (int triangleNdx = 0; triangleNdx < TRIANGLE_COUNT; triangleNdx++)
+ {
+ rr::RenderState renderState(refRenderer.getViewportState());
+
+ refRenderer.draw(renderState,
+ rr::PRIMITIVETYPE_TRIANGLES,
+ std::vector<Vertex4RGBA>(m_vertices.begin() + triangleNdx * 3,
+ m_vertices.begin() + (triangleNdx + 1) * 3));
+ }
+ }
+
+ // Compare result with reference image
+ {
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+ de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
+
+ compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+ "IntImageCompare",
+ "Image comparison",
+ refRenderer.getAccess(),
+ result->getAccess(),
+ tcu::UVec4(2, 2, 2, 2),
+ tcu::IVec3(1, 1, 0),
+ true,
+ tcu::COMPARE_LOG_RESULT);
+ }
+
+ if (compareOk)
+ return tcu::TestStatus::pass("Result image matches reference");
+ else
+ return tcu::TestStatus::fail("Image mismatch");
+}
+
+class PushConstantComputeTest : public vkt::TestCase
+{
+public:
+ PushConstantComputeTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const PushConstantData pushConstantRange);
+ virtual ~PushConstantComputeTest (void);
+ virtual void initPrograms (SourceCollections& sourceCollections) const;
+ virtual TestInstance* createInstance (Context& context) const;
+
+private:
+ const PushConstantData m_pushConstantRange;
+};
+
+class PushConstantComputeTestInstance : public vkt::TestInstance
+{
+public:
+ PushConstantComputeTestInstance (Context& context,
+ const PushConstantData pushConstantRange);
+ virtual ~PushConstantComputeTestInstance (void);
+ virtual tcu::TestStatus iterate (void);
+
+private:
+ const PushConstantData m_pushConstantRange;
+
+ Move<VkBuffer> m_outBuffer;
+ de::MovePtr<Allocation> m_outBufferAlloc;
+ Move<VkDescriptorPool> m_descriptorPool;
+ Move<VkDescriptorSetLayout> m_descriptorSetLayout;
+ Move<VkDescriptorSet> m_descriptorSet;
+
+ Move<VkPipelineLayout> m_pipelineLayout;
+ Move<VkPipeline> m_computePipelines;
+
+ Move<VkShaderModule> m_computeShaderModule;
+
+ Move<VkCommandPool> m_cmdPool;
+ Move<VkCommandBuffer> m_cmdBuffer;
+
+ Move<VkFence> m_fence;
+};
+
+PushConstantComputeTest::PushConstantComputeTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const PushConstantData pushConstantRange)
+ : vkt::TestCase (testContext, name, description)
+ , m_pushConstantRange (pushConstantRange)
+{
+}
+
+PushConstantComputeTest::~PushConstantComputeTest (void)
+{
+}
+
+TestInstance* PushConstantComputeTest::createInstance (Context& context) const
+{
+ return new PushConstantComputeTestInstance(context, m_pushConstantRange);
+}
+
+void PushConstantComputeTest::initPrograms (SourceCollections& sourceCollections) const
+{
+ std::ostringstream computeSrc;
+
+ computeSrc << "#version 450\n"
+ << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
+ << "layout(std140, set = 0, binding = 0) writeonly buffer Output {\n"
+ << " vec4 elements[];\n"
+ << "} outData;\n"
+ << "layout(push_constant) uniform Material{\n"
+ << " vec4 element;\n"
+ << "} matInst;\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " outData.elements[gl_GlobalInvocationID.x] = matInst.element;\n"
+ << "}\n";
+
+ sourceCollections.glslSources.add("compute") << glu::ComputeSource(computeSrc.str());
+}
+
+PushConstantComputeTestInstance::PushConstantComputeTestInstance (Context& context,
+ const PushConstantData pushConstantRange)
+ : vkt::TestInstance (context)
+ , m_pushConstantRange (pushConstantRange)
+{
+ const DeviceInterface& vk = context.getDeviceInterface();
+ const VkDevice vkDevice = context.getDevice();
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+
+ // Create pipeline layout
+ {
+ // create push constant range
+ VkPushConstantRange pushConstantRanges;
+ pushConstantRanges.stageFlags = m_pushConstantRange.range.shaderStage;
+ pushConstantRanges.offset = m_pushConstantRange.range.offset;
+ pushConstantRanges.size = m_pushConstantRange.range.size;
+
+ // create descriptor set layout
+ m_descriptorSetLayout = DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT).build(vk, vkDevice);
+
+ // create descriptor pool
+ m_descriptorPool = DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u).build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+
+ // create uniform buffer
+ const VkDeviceSize bufferSize = sizeof(tcu::Vec4) * 8;
+ const VkBufferCreateInfo bufferCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ bufferSize, // VkDeviceSize size;
+ VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage;
+ 0u, // VkBufferCreateFlags flags;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ m_outBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
+ m_outBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outBuffer), MemoryRequirement::HostVisible);
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
+
+ // create and update descriptor set
+ const VkDescriptorSetAllocateInfo allocInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_descriptorPool, // VkDescriptorPool descriptorPool;
+ 1u, // uint32_t setLayoutCount;
+ &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
+ };
+ m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+
+ const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*m_outBuffer, (VkDeviceSize)0u, bufferSize);
+
+ DescriptorSetUpdateBuilder()
+ .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
+ .update(vk, vkDevice);
+
+ // create pipeline layout
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineLayoutCreateFlags flags;
+ 1u, // deUint32 descriptorSetCount;
+ &(*m_descriptorSetLayout), // const VkDescriptorSetLayout* pSetLayouts;
+ 1u, // deUint32 pushConstantRangeCount;
+ &pushConstantRanges // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+ }
+
+ // create pipeline
+ {
+ m_computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0);
+
+ const VkPipelineShaderStageCreateInfo stageCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
+ *m_computeShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ };
+
+ const VkComputePipelineCreateInfo createInfo =
+ {
+ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineCreateFlags flags;
+ stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
+ *m_pipelineLayout, // VkPipelineLayout layout;
+ (VkPipeline)0, // VkPipeline basePipelineHandle;
+ 0u, // int32_t basePipelineIndex;
+ };
+
+ m_computePipelines = createComputePipeline(vk, vkDevice, (vk::VkPipelineCache)0u, &createInfo);
+ }
+
+ // Create command pool
+ {
+ const VkCommandPoolCreateInfo cmdPoolParams =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags;
+ queueFamilyIndex // deUint32 queueFamilyIndex;
+ };
+ m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+ }
+
+ // Create command buffer
+ {
+ const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_cmdPool, // VkCommandPool commandPool;
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
+ 1u // deUint32 bufferCount;
+ };
+
+ m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+ const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkCommandBufferUsageFlags flags;
+ DE_NULL, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkFramebuffer framebuffer;
+ false, // VkBool32 occlusionQueryEnable;
+ 0u, // VkQueryControlFlags queryFlags;
+ 0u // VkQueryPipelineStatisticFlags pipelineStatistics;
+ };
+
+ VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+
+ vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipelines);
+ vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0, 1, &(*m_descriptorSet), 0, DE_NULL);
+
+ // update push constant
+ tcu::Vec4 value = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+ vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange.range.shaderStage, m_pushConstantRange.range.offset, m_pushConstantRange.range.size, &value);
+
+ vk.cmdDispatch(*m_cmdBuffer, 8, 1, 1);
+
+ VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+ }
+
+ // Create fence
+ {
+ const VkFenceCreateInfo fenceParams =
+ {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u // VkFenceCreateFlags flags;
+ };
+
+ m_fence = createFence(vk, vkDevice, &fenceParams);
+ }
+}
+
+PushConstantComputeTestInstance::~PushConstantComputeTestInstance (void)
+{
+}
+
+tcu::TestStatus PushConstantComputeTestInstance::iterate (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // deUint32 waitSemaphoreCount;
+ DE_NULL, // const VkSemaphore* pWaitSemaphores;
+ 1u, // deUint32 commandBufferCount;
+ &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
+ 0u, // deUint32 signalSemaphoreCount;
+ DE_NULL // const VkSemaphore* pSignalSemaphores;
+ };
+
+ VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+ VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+ VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+ // verify result
+ std::vector<tcu::Vec4> expectValue(8, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+ if (deMemCmp((void*)(&expectValue[0]), m_outBufferAlloc->getHostPtr(), (size_t)(sizeof(tcu::Vec4) * 8)))
+ {
+ return tcu::TestStatus::fail("Image mismatch");
+ }
+ return tcu::TestStatus::pass("result image matches with reference");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createPushConstantTests (tcu::TestContext& testCtx)
+{
+ static const struct
+ {
+ const char* name;
+ const char* description;
+ deUint32 count;
+ PushConstantData range[MAX_RANGE_COUNT];
+ deBool hasMultipleUpdates;
+ } graphicsParams[] =
+ {
+ // test range size from minimum valid size to maximum
+ {
+ "range_size_4",
+ "test range size is 4 bytes(minimum valid size)",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 } , { 0, 4 } } },
+ false
+ },
+ {
+ "range_size_16",
+ "test range size is 16 bytes, and together with a normal uniform",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } } },
+ false
+ },
+ {
+ "range_size_128",
+ "test range size is 128 bytes(maximum valid size)",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 128 }, { 0, 128 } } },
+ false
+ },
+ // test range count, including all valid shader stage in graphics pipeline, and also multiple shader stages share one single range
+ {
+ "count_2_shader_VF",
+ "test range count is 2, use vertex and fragment shaders",
+ 2u,
+ {
+ { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+ { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+ },
+ false
+ },
+ {
+ "count_3shader_VGF",
+ "test range count is 3, use vertex, geometry and fragment shaders",
+ 3u,
+ {
+ { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+ { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+ { { VK_SHADER_STAGE_GEOMETRY_BIT, 20, 4 }, { 20, 4 } },
+ },
+ false
+ },
+ {
+ "count_5_shader_VTGF",
+ "test range count is 5, use vertex, tessellation, geometry and fragment shaders",
+ 5u,
+ {
+ { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+ { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+ { { VK_SHADER_STAGE_GEOMETRY_BIT, 20, 4 }, { 20, 4 } },
+ { { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 24, 4 }, { 24, 4 } },
+ { { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 28, 16 }, { 28, 16 } },
+ },
+ false
+ },
+ {
+ "count_1_shader_VF",
+ "test range count is 1, vertex and fragment shaders share one range",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4 }, { 0, 4 } } },
+ false
+ },
+ // test data partial update and multiple times update
+ {
+ "data_update_partial_1",
+ "test partial update of the values",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 4, 8 } } },
+ false
+ },
+ {
+ "data_update_partial_2",
+ "test partial update of the values",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 40 }, { 24, 16 } } },
+ false
+ },
+ {
+ "data_update_multiple",
+ "test multiple times update of the values",
+ 1u,
+ { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 }, { 0, 4 } } },
+ true
+ },
+ };
+
+ static const struct
+ {
+ const char* name;
+ const char* description;
+ PushConstantData range;
+ } computeParams[] =
+ {
+ {
+ "simple_test",
+ "test compute pipeline",
+ { { VK_SHADER_STAGE_COMPUTE_BIT, 0, 16 }, { 0, 16 } },
+ },
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> pushConstantTests (new tcu::TestCaseGroup(testCtx, "push_constant", "PushConstant tests"));
+
+ de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_pipeline", "graphics pipeline"));
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(graphicsParams); ndx++)
+ {
+ graphicsTests->addChild(new PushConstantGraphicsTest(testCtx, graphicsParams[ndx].name, graphicsParams[ndx].description, graphicsParams[ndx].count, graphicsParams[ndx].range, graphicsParams[ndx].hasMultipleUpdates));
+ }
+ pushConstantTests->addChild(graphicsTests.release());
+
+ de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute_pipeline", "compute pipeline"));
+ computeTests->addChild(new PushConstantComputeTest(testCtx, computeParams[0].name, computeParams[0].description, computeParams[0].range));
+ pushConstantTests->addChild(computeTests.release());
+
+ return pushConstantTests.release();
+}
+
+} // pipeline
+} // vkt
--- /dev/null
+#ifndef _VKTPIPELINEPUSHCONSTANTTESTS_HPP
+#define _VKTPIPELINEPUSHCONSTANTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 ARM Limited.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief PushConstant Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createPushConstantTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEPUSHCONSTANTTESTS_HPP
delete m_renderTarget;
}
+void ReferenceRenderer::colorClear(const tcu::Vec4& color)
+{
+ tcu::clear(m_colorBuffer.getAccess(), color);
+ tcu::clear(m_resolveColorBuffer.getAccess(), color);
+}
+
void ReferenceRenderer::draw (const rr::RenderState& renderState,
const rr::PrimitiveType primitive,
const std::vector<Vertex4RGBA>& vertexBuffer)
{
const tcu::Vec4 vtxTexCoord = rr::readVarying<float>(packet, context, 1, fragNdx);
const tcu::Vec4 texColor = sampleTexture(m_texture, m_sampler, vtxTexCoord, m_lod);
- const tcu::Vec4 normColor = texColor * m_textureFormatInfo.lookupScale + m_textureFormatInfo.lookupBias;
+ const tcu::Vec4 swizColor = swizzle(texColor, m_swizzle);
+ const tcu::Vec4 normColor = swizColor * m_textureFormatInfo.lookupScale + m_textureFormatInfo.lookupBias;
const tcu::Vec4 color = (normColor - m_colorFormatInfo.lookupBias) / m_colorFormatInfo.lookupScale;
- const tcu::Vec4 outColor = swizzle(color, m_swizzle);
- rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, outColor);
+ rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
}
}
}
virtual ~ReferenceRenderer (void);
+ void colorClear (const tcu::Vec4& color);
+
void draw (const rr::RenderState& renderState,
const rr::PrimitiveType primitive,
const std::vector<Vertex4RGBA>& vertexBuffer);
std::vector<Vertex4Tex4> SamplerTest::createVertices (void) const
{
- return createTestQuadMosaic(m_imageViewType);
+ std::vector<Vertex4Tex4> vertices = createTestQuadMosaic(m_imageViewType);
+ // Adjust texture coordinate to avoid doing NEAREST filtering exactly on texel boundaries.
+ // TODO: Would be nice to base this on number of texels and subtexel precision. But this
+ // seems to work.
+ for (unsigned int i = 0; i < vertices.size(); ++i) {
+ vertices[i].texCoord += tcu::Vec4(0.001f, 0.001f, 0.001f, 0.0f);
+ }
+ return vertices;
}
VkSamplerCreateInfo SamplerTest::getSamplerCreateInfo (void) const
{
VkSamplerCreateInfo samplerParams = SamplerTest::getSamplerCreateInfo();
samplerParams.minFilter = m_minFilter;
+ // set minLod to epsilon, to force use of the minFilter
+ samplerParams.minLod = 0.01f;
return samplerParams;
}
{
MovePtr<tcu::TestCaseGroup> samplerMagFilterTests (new tcu::TestCaseGroup(testCtx, "mag_filter", "Tests for magnification filter"));
- samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "linear", "Magnifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
+ if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+ samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "linear", "Magnifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "nearest", "Magnifies image using VK_TEX_FILTER_NEAREST", imageViewType, imageFormat, VK_FILTER_NEAREST));
return samplerMagFilterTests;
{
MovePtr<tcu::TestCaseGroup> samplerMinFilterTests (new tcu::TestCaseGroup(testCtx, "min_filter", "Tests for minification filter"));
- samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "linear", "Minifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
+ if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+ samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "linear", "Minifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "nearest", "Minifies image using VK_TEX_FILTER_NEAREST", imageViewType, imageFormat, VK_FILTER_NEAREST));
return samplerMinFilterTests;
samplerMipmapTests->addChild(mipmapNearestTests.release());
// Mipmap mode: linear
- MovePtr<tcu::TestCaseGroup> mipmapLinearTests (new tcu::TestCaseGroup(testCtx, "linear", "Uses VK_TEX_MIPMAP_MODE_LINEAR"));
- mipmapLinearTests->addChild(createSamplerLodTests(testCtx, imageViewType, imageFormat, VK_SAMPLER_MIPMAP_MODE_LINEAR).release());
- samplerMipmapTests->addChild(mipmapLinearTests.release());
+ if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+ {
+ MovePtr<tcu::TestCaseGroup> mipmapLinearTests(new tcu::TestCaseGroup(testCtx, "linear", "Uses VK_TEX_MIPMAP_MODE_LINEAR"));
+ mipmapLinearTests->addChild(createSamplerLodTests(testCtx, imageViewType, imageFormat, VK_SAMPLER_MIPMAP_MODE_LINEAR).release());
+ samplerMipmapTests->addChild(mipmapLinearTests.release());
+ }
return samplerMipmapTests;
}
#include "vktPipelineBlendTests.hpp"
#include "vktPipelineDepthTests.hpp"
#include "vktPipelineImageTests.hpp"
+#include "vktPipelineInputAssemblyTests.hpp"
#include "vktPipelineSamplerTests.hpp"
#include "vktPipelineImageViewTests.hpp"
+#include "vktPipelinePushConstantTests.hpp"
+#include "vktPipelineMultisampleTests.hpp"
+#include "vktPipelineVertexInputTests.hpp"
#include "deUniquePtr.hpp"
namespace vkt
{
de::MovePtr<tcu::TestCaseGroup> pipelineTests (new tcu::TestCaseGroup(testCtx, "pipeline", "Pipeline Tests"));
- pipelineTests->addChild(createStencilTests(testCtx));
- pipelineTests->addChild(createBlendTests(testCtx));
- pipelineTests->addChild(createDepthTests(testCtx));
- pipelineTests->addChild(createImageTests(testCtx));
- pipelineTests->addChild(createSamplerTests(testCtx));
- pipelineTests->addChild(createImageViewTests(testCtx));
+ pipelineTests->addChild(createStencilTests (testCtx));
+ pipelineTests->addChild(createBlendTests (testCtx));
+ pipelineTests->addChild(createDepthTests (testCtx));
+ pipelineTests->addChild(createImageTests (testCtx));
+ pipelineTests->addChild(createSamplerTests (testCtx));
+ pipelineTests->addChild(createImageViewTests (testCtx));
+ pipelineTests->addChild(createPushConstantTests (testCtx));
+ pipelineTests->addChild(createMultisampleTests (testCtx));
+ pipelineTests->addChild(createVertexInputTests (testCtx));
+ pipelineTests->addChild(createInputAssemblyTests(testCtx));
return pipelineTests.release();
}
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vertex Input Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineVertexInputTests.hpp"
+#include "vktPipelineCombinationsIterator.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuFloat.hpp"
+#include "tcuImageCompare.hpp"
+#include "deFloat16.h"
+#include "deMemory.h"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+bool isSupportedVertexFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
+{
+ VkFormatProperties formatProps;
+ deMemset(&formatProps, 0, sizeof(VkFormatProperties));
+ instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
+
+ return (formatProps.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0u;
+}
+
+float getRepresentableDifferenceUnorm (VkFormat format)
+{
+ DE_ASSERT(isVertexFormatUnorm(format) || isVertexFormatSRGB(format));
+
+ return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8)) - 1);
+}
+
+float getRepresentableDifferenceSnorm (VkFormat format)
+{
+ DE_ASSERT(isVertexFormatSnorm(format));
+
+ return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8 - 1)) - 1);
+}
+
+class VertexInputTest : public vkt::TestCase
+{
+public:
+ enum GlslType
+ {
+ GLSL_TYPE_INT,
+ GLSL_TYPE_IVEC2,
+ GLSL_TYPE_IVEC3,
+ GLSL_TYPE_IVEC4,
+
+ GLSL_TYPE_UINT,
+ GLSL_TYPE_UVEC2,
+ GLSL_TYPE_UVEC3,
+ GLSL_TYPE_UVEC4,
+
+ GLSL_TYPE_FLOAT,
+ GLSL_TYPE_VEC2,
+ GLSL_TYPE_VEC3,
+ GLSL_TYPE_VEC4,
+ GLSL_TYPE_MAT2,
+ GLSL_TYPE_MAT3,
+ GLSL_TYPE_MAT4,
+
+ GLSL_TYPE_DOUBLE,
+ GLSL_TYPE_DVEC2,
+ GLSL_TYPE_DVEC3,
+ GLSL_TYPE_DVEC4,
+ GLSL_TYPE_DMAT2,
+ GLSL_TYPE_DMAT3,
+ GLSL_TYPE_DMAT4,
+
+ GLSL_TYPE_COUNT
+ };
+
+ enum GlslBasicType
+ {
+ GLSL_BASIC_TYPE_INT,
+ GLSL_BASIC_TYPE_UINT,
+ GLSL_BASIC_TYPE_FLOAT,
+ GLSL_BASIC_TYPE_DOUBLE
+ };
+
+ enum BindingMapping
+ {
+ BINDING_MAPPING_ONE_TO_ONE, // Vertex input bindings will not contain data for more than one attribute.
+ BINDING_MAPPING_ONE_TO_MANY // Vertex input bindings can contain data for more than one attribute.
+ };
+
+ struct AttributeInfo
+ {
+ GlslType glslType;
+ VkFormat vkType;
+ VkVertexInputRate inputRate;
+ };
+
+ struct GlslTypeDescription
+ {
+ const char* name;
+ int vertexInputComponentCount;
+ int vertexInputCount;
+ GlslBasicType basicType;
+ };
+
+ static const GlslTypeDescription s_glslTypeDescriptions[GLSL_TYPE_COUNT];
+
+ VertexInputTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const std::vector<AttributeInfo>& attributeInfos,
+ BindingMapping bindingMapping);
+
+ virtual ~VertexInputTest (void) {}
+ virtual void initPrograms (SourceCollections& programCollection) const;
+ virtual TestInstance* createInstance (Context& context) const;
+ static bool isCompatibleType (VkFormat format, GlslType glslType);
+
+private:
+ std::string getGlslInputDeclarations (void) const;
+ std::string getGlslVertexCheck (void) const;
+ std::string getGlslAttributeConditions (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const;
+ static tcu::Vec4 getFormatThreshold (VkFormat format);
+
+ const std::vector<AttributeInfo> m_attributeInfos;
+ const BindingMapping m_bindingMapping;
+};
+
+class GlslTypeCombinationsIterator : public CombinationsIterator< std::vector<VertexInputTest::GlslType> >
+{
+public:
+ GlslTypeCombinationsIterator (deUint32 numValues, deUint32 combinationSize);
+ virtual ~GlslTypeCombinationsIterator (void) {}
+
+protected:
+ virtual std::vector<VertexInputTest::GlslType> getCombinationValue (const std::vector<deUint32>& combination);
+
+private:
+ std::vector<VertexInputTest::GlslType> m_combinationValue;
+};
+
+class VertexInputInstance : public vkt::TestInstance
+{
+public:
+ struct VertexInputAttributeDescription
+ {
+ VertexInputTest::GlslType glslType;
+ int vertexInputIndex;
+ VkVertexInputAttributeDescription vkDescription;
+ };
+
+ typedef std::vector<VertexInputAttributeDescription> AttributeDescriptionList;
+
+ VertexInputInstance (Context& context,
+ const AttributeDescriptionList& attributeDescriptions,
+ const std::vector<VkVertexInputBindingDescription>& bindingDescriptions,
+ const std::vector<VkDeviceSize>& bindingOffsets);
+
+ virtual ~VertexInputInstance (void);
+ virtual tcu::TestStatus iterate (void);
+
+
+ static void writeVertexInputData (deUint8* destPtr, const VkVertexInputBindingDescription& bindingDescription, const VkDeviceSize bindingOffset, const AttributeDescriptionList& attributes);
+ static void writeVertexInputValue (deUint8* destPtr, const VertexInputAttributeDescription& attributes, int indexId);
+
+private:
+ tcu::TestStatus verifyImage (void);
+
+private:
+ std::vector<VkBuffer> m_vertexBuffers;
+ std::vector<Allocation*> m_vertexBufferAllocs;
+
+ const tcu::IVec2 m_renderSize;
+ const VkFormat m_colorFormat;
+
+ Move<VkImage> m_colorImage;
+ de::MovePtr<Allocation> m_colorImageAlloc;
+ Move<VkImage> m_depthImage;
+ Move<VkImageView> m_colorAttachmentView;
+ Move<VkRenderPass> m_renderPass;
+ Move<VkFramebuffer> m_framebuffer;
+
+ Move<VkShaderModule> m_vertexShaderModule;
+ Move<VkShaderModule> m_fragmentShaderModule;
+
+ Move<VkPipelineLayout> m_pipelineLayout;
+ Move<VkPipeline> m_graphicsPipeline;
+
+ Move<VkCommandPool> m_cmdPool;
+ Move<VkCommandBuffer> m_cmdBuffer;
+
+ Move<VkFence> m_fence;
+};
+
+const VertexInputTest::GlslTypeDescription VertexInputTest::s_glslTypeDescriptions[GLSL_TYPE_COUNT] =
+{
+ { "int", 1, 1, GLSL_BASIC_TYPE_INT },
+ { "ivec2", 2, 1, GLSL_BASIC_TYPE_INT },
+ { "ivec3", 3, 1, GLSL_BASIC_TYPE_INT },
+ { "ivec4", 4, 1, GLSL_BASIC_TYPE_INT },
+
+ { "uint", 1, 1, GLSL_BASIC_TYPE_UINT },
+ { "uvec2", 2, 1, GLSL_BASIC_TYPE_UINT },
+ { "uvec3", 3, 1, GLSL_BASIC_TYPE_UINT },
+ { "uvec4", 4, 1, GLSL_BASIC_TYPE_UINT },
+
+ { "float", 1, 1, GLSL_BASIC_TYPE_FLOAT },
+ { "vec2", 2, 1, GLSL_BASIC_TYPE_FLOAT },
+ { "vec3", 3, 1, GLSL_BASIC_TYPE_FLOAT },
+ { "vec4", 4, 1, GLSL_BASIC_TYPE_FLOAT },
+ { "mat2", 2, 2, GLSL_BASIC_TYPE_FLOAT },
+ { "mat3", 3, 3, GLSL_BASIC_TYPE_FLOAT },
+ { "mat4", 4, 4, GLSL_BASIC_TYPE_FLOAT },
+
+ { "double", 1, 1, GLSL_BASIC_TYPE_DOUBLE },
+ { "dvec2", 2, 1, GLSL_BASIC_TYPE_DOUBLE },
+ { "dvec3", 3, 1, GLSL_BASIC_TYPE_DOUBLE },
+ { "dvec4", 4, 1, GLSL_BASIC_TYPE_DOUBLE },
+ { "dmat2", 2, 2, GLSL_BASIC_TYPE_DOUBLE },
+ { "dmat3", 3, 3, GLSL_BASIC_TYPE_DOUBLE },
+ { "dmat4", 4, 4, GLSL_BASIC_TYPE_DOUBLE }
+};
+
+
+VertexInputTest::VertexInputTest (tcu::TestContext& testContext,
+ const std::string& name,
+ const std::string& description,
+ const std::vector<AttributeInfo>& attributeInfos,
+ BindingMapping bindingMapping)
+
+ : vkt::TestCase (testContext, name, description)
+ , m_attributeInfos (attributeInfos)
+ , m_bindingMapping (bindingMapping)
+{
+}
+
+TestInstance* VertexInputTest::createInstance (Context& context) const
+{
+ // Create enough binding descriptions with random offsets
+ std::vector<VkVertexInputBindingDescription> bindingDescriptions;
+ std::vector<VkDeviceSize> bindingOffsets;
+
+ for (size_t bindingNdx = 0; bindingNdx < m_attributeInfos.size() * 2; bindingNdx++)
+ {
+ // Use STEP_RATE_VERTEX in even bindings and STEP_RATE_INSTANCE in odd bindings
+ const VkVertexInputRate inputRate = (bindingNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+
+ // .strideInBytes will be updated when creating the attribute descriptions
+ const VkVertexInputBindingDescription bindingDescription =
+ {
+ (deUint32)bindingNdx, // deUint32 binding;
+ 0, // deUint32 stride;
+ inputRate // VkVertexInputRate inputRate;
+ };
+
+ bindingDescriptions.push_back(bindingDescription);
+ bindingOffsets.push_back(4 * bindingNdx);
+ }
+
+ // Create attribute descriptions, assign them to bindings and update .strideInBytes
+ std::vector<VertexInputInstance::VertexInputAttributeDescription> attributeDescriptions;
+ deUint32 attributeLocation = 0;
+ std::vector<deUint32> attributeOffsets (bindingDescriptions.size(), 0);
+
+ for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+ {
+ const AttributeInfo& attributeInfo = m_attributeInfos[attributeNdx];
+ const GlslTypeDescription& glslTypeDescription = s_glslTypeDescriptions[attributeInfo.glslType];
+ const deUint32 inputSize = getVertexFormatSize(attributeInfo.vkType);
+ deUint32 attributeBinding;
+
+ if (m_bindingMapping == BINDING_MAPPING_ONE_TO_ONE)
+ {
+ if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+ {
+ attributeBinding = (deUint32)attributeNdx * 2; // Odd binding number
+ }
+ else // attributeInfo.inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
+ {
+ attributeBinding = (deUint32)attributeNdx * 2 + 1; // Even binding number
+ }
+ }
+ else // m_bindingMapping == BINDING_MAPPING_ONE_TO_MANY
+ {
+ if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+ {
+ attributeBinding = 0;
+ }
+ else // attributeInfo.inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
+ {
+ attributeBinding = 1;
+ }
+ }
+
+ for (int descNdx = 0; descNdx < glslTypeDescription.vertexInputCount; descNdx++)
+ {
+ const VertexInputInstance::VertexInputAttributeDescription attributeDescription =
+ {
+ attributeInfo.glslType, // GlslType glslType;
+ descNdx, // int index;
+ {
+ attributeLocation, // deUint32 location;
+ attributeBinding, // deUint32 binding;
+ attributeInfo.vkType, // VkFormat format;
+ attributeOffsets[attributeBinding], // deUint32 offset;
+ },
+ };
+
+ bindingDescriptions[attributeBinding].stride += inputSize;
+ attributeOffsets[attributeBinding] += inputSize;
+
+ attributeLocation++;
+
+ attributeDescriptions.push_back(attributeDescription);
+ }
+ }
+
+ return new VertexInputInstance(context, attributeDescriptions, bindingDescriptions, bindingOffsets);
+}
+
+void VertexInputTest::initPrograms (SourceCollections& programCollection) const
+{
+ std::ostringstream vertexSrc;
+
+ vertexSrc << "#version 440\n"
+ << getGlslInputDeclarations()
+ << "layout(location = 0) out highp vec4 vtxColor;\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "double abs (double x) { if (x < 0.0LF) return -x; else return x; }\n" // NOTE: Currently undefined in glslang ??
+ << "void main (void)\n"
+ << "{\n"
+ << getGlslVertexCheck()
+ << "}\n";
+
+ programCollection.glslSources.add("attribute_test_vert") << glu::VertexSource(vertexSrc.str());
+
+ programCollection.glslSources.add("attribute_test_frag") << glu::FragmentSource(
+ "#version 440\n"
+ "layout(location = 0) in highp vec4 vtxColor;\n"
+ "layout(location = 0) out highp vec4 fragColor;\n"
+ "void main (void)\n"
+ "{\n"
+ " fragColor = vtxColor;\n"
+ "}\n");
+}
+
+std::string VertexInputTest::getGlslInputDeclarations (void) const
+{
+ std::ostringstream glslInputs;
+ deUint32 location = 0;
+
+ for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+ {
+ const GlslTypeDescription& glslTypeDesc = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType];
+
+ glslInputs << "layout(location = " << location << ") in highp " << glslTypeDesc.name << " attr" << attributeNdx << ";\n";
+ location += glslTypeDesc.vertexInputCount;
+ }
+
+ return glslInputs.str();
+}
+
+std::string VertexInputTest::getGlslVertexCheck (void) const
+{
+ std::ostringstream glslCode;
+ int totalInputComponentCount = 0;
+
+
+ glslCode << " int okCount = 0;\n";
+
+ for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+ {
+ glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], (deUint32)attributeNdx);
+
+ const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
+ totalInputComponentCount += vertexInputCount * VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputComponentCount;
+ }
+
+ glslCode <<
+ " if (okCount == " << totalInputComponentCount << ")\n"
+ " {\n"
+ " if (gl_InstanceID == 0)\n"
+ " vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
+ " else\n"
+ " vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " vtxColor = vec4(okCount / float(" << totalInputComponentCount << "), 0.0f, 0.0f, 1.0);\n" <<
+ " }\n\n"
+ " if (gl_InstanceID == 0)\n"
+ " {\n"
+ " if (gl_VertexID == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ " else gl_Position = vec4(0.0);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " if (gl_VertexID == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ " else if (gl_VertexID == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
+ " else gl_Position = vec4(0.0);\n"
+ " }\n";
+
+ return glslCode.str();
+}
+
+std::string VertexInputTest::getGlslAttributeConditions (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const
+{
+ std::ostringstream glslCode;
+ std::ostringstream attributeVar;
+ const std::string indexId = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexID" : "gl_InstanceID";
+ const int componentCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
+ const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
+ const deUint32 totalComponentCount = componentCount * vertexInputCount;
+ const tcu::Vec4 threshold = getFormatThreshold(attributeInfo.vkType);
+ deUint32 componentIndex = 0;
+
+ attributeVar << "attr" << attributeIndex;
+
+ glslCode << std::fixed;
+
+ for (int columnNdx = 0; columnNdx< vertexInputCount; columnNdx++)
+ {
+ for (int rowNdx = 0; rowNdx < componentCount; rowNdx++)
+ {
+ std::string accessStr;
+ {
+ // Build string representing the access to the attribute component
+ std::ostringstream accessStream;
+ accessStream << attributeVar.str();
+
+ if (vertexInputCount == 1)
+ {
+ if (componentCount > 1)
+ accessStream << "[" << rowNdx << "]";
+ }
+ else
+ {
+ accessStream << "[" << columnNdx << "][" << rowNdx << "]";
+ }
+
+ accessStr = accessStream.str();
+ }
+
+ if (isVertexFormatSint(attributeInfo.vkType))
+ {
+ glslCode << "\tif (" << accessStr << " == -(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+ }
+ else if (isVertexFormatUint(attributeInfo.vkType))
+ {
+ glslCode << "\tif (" << accessStr << " == uint(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+ }
+ else if (isVertexFormatSfloat(attributeInfo.vkType))
+ {
+ if (VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
+ {
+ glslCode << "\tif (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double(" << threshold[rowNdx] << "))\n";
+ }
+ else
+ {
+ glslCode << "\tif (abs(" << accessStr << " + (0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+ }
+ }
+ else if (isVertexFormatSscaled(attributeInfo.vkType))
+ {
+ glslCode << "\tif (abs(" << accessStr << " + (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+ }
+ else if (isVertexFormatUscaled(attributeInfo.vkType))
+ {
+ glslCode << "\t if (abs(" << accessStr << " - (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+ }
+ else if (isVertexFormatSnorm(attributeInfo.vkType))
+ {
+ const float representableDiff = getRepresentableDifferenceSnorm(attributeInfo.vkType);
+
+ glslCode << "\tif (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+ }
+ else if (isVertexFormatUnorm(attributeInfo.vkType) || isVertexFormatSRGB(attributeInfo.vkType))
+ {
+ const float representableDiff = getRepresentableDifferenceUnorm(attributeInfo.vkType);
+
+ glslCode << "\tif (abs(" << accessStr << " - " << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+ }
+ else
+ {
+ DE_ASSERT(false);
+ }
+
+ glslCode << "\t\tokCount++;\n\n";
+
+ componentIndex++;
+ }
+ }
+ return glslCode.str();
+}
+
+tcu::Vec4 VertexInputTest::getFormatThreshold (VkFormat format)
+{
+ using tcu::Vec4;
+
+ switch (format)
+ {
+ case VK_FORMAT_R32_SFLOAT:
+ case VK_FORMAT_R32G32_SFLOAT:
+ case VK_FORMAT_R32G32B32_SFLOAT:
+ case VK_FORMAT_R32G32B32A32_SFLOAT:
+ case VK_FORMAT_R64_SFLOAT:
+ case VK_FORMAT_R64G64_SFLOAT:
+ case VK_FORMAT_R64G64B64_SFLOAT:
+ case VK_FORMAT_R64G64B64A64_SFLOAT:
+ return Vec4(0.00001f);
+
+ default:
+ break;
+ }
+
+ if (isVertexFormatSnorm(format))
+ {
+ return Vec4(1.5f * getRepresentableDifferenceSnorm(format));
+ }
+ else if (isVertexFormatUnorm(format))
+ {
+ return Vec4(1.5f * getRepresentableDifferenceUnorm(format));
+ }
+
+ return Vec4(0.001f);
+}
+
+GlslTypeCombinationsIterator::GlslTypeCombinationsIterator (deUint32 numValues, deUint32 combinationSize)
+ : CombinationsIterator< std::vector<VertexInputTest::GlslType> > (numValues, combinationSize)
+ , m_combinationValue (std::vector<VertexInputTest::GlslType>(combinationSize))
+{
+ DE_ASSERT(numValues <= VertexInputTest::GLSL_TYPE_COUNT);
+}
+
+std::vector<VertexInputTest::GlslType> GlslTypeCombinationsIterator::getCombinationValue (const std::vector<deUint32>& combination)
+{
+ for (size_t combinationItemNdx = 0; combinationItemNdx < combination.size(); combinationItemNdx++)
+ m_combinationValue[combinationItemNdx] = (VertexInputTest::GlslType)combination[combinationItemNdx];
+
+ return m_combinationValue;
+}
+
+VertexInputInstance::VertexInputInstance (Context& context,
+ const AttributeDescriptionList& attributeDescriptions,
+ const std::vector<VkVertexInputBindingDescription>& bindingDescriptions,
+ const std::vector<VkDeviceSize>& bindingOffsets)
+ : vkt::TestInstance (context)
+ , m_renderSize (16, 16)
+ , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
+{
+ DE_ASSERT(bindingDescriptions.size() == bindingOffsets.size());
+
+ const DeviceInterface& vk = context.getDeviceInterface();
+ const VkDevice vkDevice = context.getDevice();
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+ const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+ // Create color image
+ {
+ const VkImageCreateInfo colorImageParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ m_colorFormat, // VkFormat format;
+ { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ m_colorImage = createImage(vk, vkDevice, &colorImageParams);
+
+ // Allocate and bind color image memory
+ m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+ VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+ }
+
+ // Create color attachment view
+ {
+ const VkImageViewCreateInfo colorAttachmentViewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ *m_colorImage, // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ m_colorFormat, // VkFormat format;
+ componentMappingRGBA, // VkComponentMapping components;
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange;
+ };
+
+ m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+ }
+
+ // Create render pass
+ {
+ const VkAttachmentDescription colorAttachmentDescription =
+ {
+ 0u, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentReference colorAttachmentReference =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkSubpassDescription subpassDescription =
+ {
+ 0u, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ 0u, // deUint32 inputAttachmentCount;
+ DE_NULL, // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
+ DE_NULL, // const VkAttachmentReference* pResolveAttachments;
+ DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const VkAttachmentReference* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassParams =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkRenderPassCreateFlags flags;
+ 1u, // deUint32 attachmentCount;
+ &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+ }
+
+ // Create framebuffer
+ {
+ const VkFramebufferCreateInfo framebufferParams =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkFramebufferCreateFlags flags;
+ *m_renderPass, // VkRenderPass renderPass;
+ 1u, // deUint32 attachmentCount;
+ &m_colorAttachmentView.get(), // const VkImageView* pAttachments;
+ (deUint32)m_renderSize.x(), // deUint32 width;
+ (deUint32)m_renderSize.y(), // deUint32 height;
+ 1u // deUint32 layers;
+ };
+
+ m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+ }
+
+ // Create pipeline layout
+ {
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineLayoutCreateFlags flags;
+ 0u, // deUint32 setLayoutCount;
+ DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
+ 0u, // deUint32 pushConstantRangeCount;
+ DE_NULL // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+ }
+
+ m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_vert"), 0);
+ m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_frag"), 0);
+
+
+ // Create pipeline
+ {
+ const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+ {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
+ *m_vertexShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
+ *m_fragmentShaderModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
+ }
+ };
+
+ // Create vertex attribute array and check if their VK formats are supported
+ std::vector<VkVertexInputAttributeDescription> vkAttributeDescriptions;
+ for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
+ {
+ const VkVertexInputAttributeDescription& attributeDescription = attributeDescriptions[attributeNdx].vkDescription;
+
+ if (!isSupportedVertexFormat(context.getInstanceInterface(), context.getPhysicalDevice(), attributeDescription.format))
+ throw tcu::NotSupportedError(std::string("Unsupported format for vertex input: ") + getFormatName(attributeDescription.format));
+
+ vkAttributeDescriptions.push_back(attributeDescription);
+ }
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineVertexInputStateCreateFlags flags;
+ (deUint32)bindingDescriptions.size(), // deUint32 vertexBindingDescriptionCount;
+ bindingDescriptions.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
+ (deUint32)vkAttributeDescriptions.size(), // deUint32 vertexAttributeDescriptionCount;
+ vkAttributeDescriptions.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
+ };
+
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology;
+ false // VkBool32 primitiveRestartEnable;
+ };
+
+ const VkViewport viewport =
+ {
+ 0.0f, // float x;
+ 0.0f, // float y;
+ (float)m_renderSize.x(), // float width;
+ (float)m_renderSize.y(), // float height;
+ 0.0f, // float minDepth;
+ 1.0f // float maxDepth;
+ };
+
+ const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+ const VkPipelineViewportStateCreateInfo viewportStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineViewportStateCreateFlags flags;
+ 1u, // deUint32 viewportCount;
+ &viewport, // const VkViewport* pViewports;
+ 1u, // deUint32 scissorCount;
+ &scissor // const VkRect2D* pScissors;
+ };
+
+ const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineRasterizationStateCreateFlags flags;
+ false, // VkBool32 depthClampEnable;
+ false, // VkBool32 rasterizerDiscardEnable;
+ VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
+ VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FALSE, // VkBool32 depthBiasEnable;
+ 0.0f, // float depthBiasConstantFactor;
+ 0.0f, // float depthBiasClamp;
+ 0.0f, // float depthBiasSlopeFactor;
+ 1.0f, // float lineWidth;
+ };
+
+ const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+ {
+ false, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+ };
+
+ const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineColorBlendStateCreateFlags flags;
+ false, // VkBool32 logicOpEnable;
+ VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
+ 1u, // deUint32 attachmentCount;
+ &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
+ { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
+ };
+
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ false, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ false, // VkBool32 alphaToCoverageEnable;
+ false // VkBool32 alphaToOneEnable;
+ };
+
+ const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDynamicStateCreateFlags flags;
+ 0u, // deUint32 dynamicStateCount;
+ DE_NULL // const VkDynamicState* pDynamicStates;
+ };
+
+ VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineDepthStencilStateCreateFlags flags;
+ false, // VkBool32 depthTestEnable;
+ false, // VkBool32 depthWriteEnable;
+ VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
+ false, // VkBool32 depthBoundsTestEnable;
+ false, // VkBool32 stencilTestEnable;
+ // VkStencilOpState front;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ // VkStencilOpState back;
+ {
+ VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
+ VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0u, // deUint32 compareMask;
+ 0u, // deUint32 writeMask;
+ 0u, // deUint32 reference;
+ },
+ -1.0f, // float minDepthBounds;
+ +1.0f, // float maxDepthBounds;
+ };
+
+ const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+ {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineCreateFlags flags;
+ 2u, // deUint32 stageCount;
+ shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages;
+ &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+ &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+ DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
+ &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+ &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
+ &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
+ *m_pipelineLayout, // VkPipelineLayout layout;
+ *m_renderPass, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ 0u, // VkPipeline basePipelineHandle;
+ 0u // deInt32 basePipelineIndex;
+ };
+
+ m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+ }
+
+ // Create vertex buffer
+ {
+ const VkBufferCreateInfo vertexBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkBufferCreateFlags flags;
+ 4096u, // VkDeviceSize size;
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyIndexCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ // Upload data for each vertex input binding
+ for (deUint32 bindingNdx = 0; bindingNdx < bindingDescriptions.size(); bindingNdx++)
+ {
+ Move<VkBuffer> vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
+ de::MovePtr<Allocation> vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
+
+ VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset()));
+
+ writeVertexInputData((deUint8*)vertexBufferAlloc->getHostPtr(), bindingDescriptions[bindingNdx], bindingOffsets[bindingNdx], attributeDescriptions);
+ flushMappedMemoryRange(vk, vkDevice, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+
+ m_vertexBuffers.push_back(vertexBuffer.disown());
+ m_vertexBufferAllocs.push_back(vertexBufferAlloc.release());
+ }
+ }
+
+ // Create command pool
+ {
+ const VkCommandPoolCreateInfo cmdPoolParams =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
+ queueFamilyIndex, // deUint32 queueFamilyIndex;
+ };
+
+ m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+ }
+
+ // Create command buffer
+ {
+ const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_cmdPool, // VkCommandPool commandPool;
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
+ 1u // deUint32 bufferCount;
+ };
+
+ const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkCommandBufferUsageFlags flags;
+ DE_NULL, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkFramebuffer framebuffer;
+ false, // VkBool32 occlusionQueryEnable;
+ 0u, // VkQueryControlFlags queryFlags;
+ 0u // VkQueryPipelineStatisticFlags pipelineStatistics;
+ };
+
+ const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
+
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *m_renderPass, // VkRenderPass renderPass;
+ *m_framebuffer, // VkFramebuffer framebuffer;
+ { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea;
+ 1u, // deUint32 clearValueCount;
+ &attachmentClearValue // const VkClearValue* pClearValues;
+ };
+
+ m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+ VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+ vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+
+ std::vector<VkBuffer> vertexBuffers;
+ for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
+ vertexBuffers.push_back(m_vertexBuffers[bufferNdx]);
+
+ if (vertexBuffers.size() <= 1)
+ {
+ // One vertex buffer
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, (deUint32)vertexBuffers.size(), vertexBuffers.data(), bindingOffsets.data());
+ }
+ else
+ {
+ // Smoke-test vkCmdBindVertexBuffers(..., startBinding, ... )
+
+ const deUint32 firstHalfLength = (deUint32)vertexBuffers.size() / 2;
+ const deUint32 secondHalfLength = firstHalfLength + (deUint32)(vertexBuffers.size() % 2);
+
+ // Bind first half of vertex buffers
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, firstHalfLength, vertexBuffers.data(), bindingOffsets.data());
+
+ // Bind second half of vertex buffers
+ vk.cmdBindVertexBuffers(*m_cmdBuffer, firstHalfLength, secondHalfLength,
+ vertexBuffers.data() + firstHalfLength,
+ bindingOffsets.data() + firstHalfLength);
+ }
+
+ vk.cmdDraw(*m_cmdBuffer, 4, 2, 0, 0);
+
+ vk.cmdEndRenderPass(*m_cmdBuffer);
+ VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+ }
+
+ // Create fence
+ {
+ const VkFenceCreateInfo fenceParams =
+ {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u // VkFenceCreateFlags flags;
+ };
+
+ m_fence = createFence(vk, vkDevice, &fenceParams);
+ }
+}
+
+VertexInputInstance::~VertexInputInstance (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+
+ for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
+ vk.destroyBuffer(vkDevice, m_vertexBuffers[bufferNdx], DE_NULL);
+
+ for (size_t allocNdx = 0; allocNdx < m_vertexBufferAllocs.size(); allocNdx++)
+ delete m_vertexBufferAllocs[allocNdx];
+}
+
+void VertexInputInstance::writeVertexInputData(deUint8* destPtr, const VkVertexInputBindingDescription& bindingDescription, const VkDeviceSize bindingOffset, const AttributeDescriptionList& attributes)
+{
+ const deUint32 vertexCount = (bindingDescription.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
+
+ deUint8* destOffsetPtr = ((deUint8 *)destPtr) + bindingOffset;
+ for (deUint32 vertexNdx = 0; vertexNdx < vertexCount; vertexNdx++)
+ {
+ deUint32 vertexInputOffset = 0;
+ for (size_t attributeNdx = 0; attributeNdx < attributes.size(); attributeNdx++)
+ {
+ const VertexInputAttributeDescription& attribDesc = attributes[attributeNdx];
+
+ // Only write vertex input data to bindings referenced by attribute descriptions
+ if (attribDesc.vkDescription.binding == bindingDescription.binding)
+ {
+ writeVertexInputValue(destOffsetPtr + vertexInputOffset, attribDesc, vertexNdx);
+ vertexInputOffset += getVertexFormatSize(attribDesc.vkDescription.format);
+ }
+ }
+ DE_ASSERT(vertexInputOffset <= bindingDescription.stride);
+ destOffsetPtr += bindingDescription.stride;
+ }
+}
+
+void writeVertexInputValueSint (deUint8* destPtr, VkFormat format, int componentNdx, deInt32 value)
+{
+ const deUint32 componentSize = getVertexFormatComponentSize(format);
+ deUint8* destFormatPtr = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+ switch (componentSize)
+ {
+ case 1:
+ *((deInt8*)destFormatPtr) = (deInt8)value;
+ break;
+
+ case 2:
+ *((deInt16*)destFormatPtr) = (deInt16)value;
+ break;
+
+ case 4:
+ *((deInt32*)destFormatPtr) = (deInt32)value;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+}
+
+void writeVertexInputValueUint (deUint8* destPtr, VkFormat format, int componentNdx, deUint32 value)
+{
+ const deUint32 componentSize = getVertexFormatComponentSize(format);
+ deUint8* destFormatPtr = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+ switch (componentSize)
+ {
+ case 1:
+ *((deUint8 *)destFormatPtr) = (deUint8)value;
+ break;
+
+ case 2:
+ *((deUint16 *)destFormatPtr) = (deUint16)value;
+ break;
+
+ case 4:
+ *((deUint32 *)destFormatPtr) = (deUint32)value;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+}
+
+void writeVertexInputValueSfloat (deUint8* destPtr, VkFormat format, int componentNdx, float value)
+{
+ const deUint32 componentSize = getVertexFormatComponentSize(format);
+ deUint8* destFormatPtr = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+ switch (componentSize)
+ {
+ case 2:
+ *((deFloat16*)destFormatPtr) = deFloat32To16(value);
+ break;
+
+ case 4:
+ *((float*)destFormatPtr) = value;
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+}
+
+void VertexInputInstance::writeVertexInputValue (deUint8* destPtr, const VertexInputAttributeDescription& attribute, int indexId)
+{
+ const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputCount;
+ const int componentCount = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputComponentCount;
+ const deUint32 totalComponentCount = componentCount * vertexInputCount;
+ const deUint32 vertexInputIndex = indexId * totalComponentCount + attribute.vertexInputIndex * componentCount;
+ const bool hasBGROrder = isVertexFormatComponentOrderBGR(attribute.vkDescription.format);
+ int swizzledNdx;
+
+ for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
+ {
+ if (hasBGROrder)
+ {
+ if (componentNdx == 0)
+ swizzledNdx = 2;
+ else if (componentNdx == 2)
+ swizzledNdx = 0;
+ else
+ swizzledNdx = componentNdx;
+ }
+ else
+ swizzledNdx = componentNdx;
+
+ switch (attribute.glslType)
+ {
+ case VertexInputTest::GLSL_TYPE_INT:
+ case VertexInputTest::GLSL_TYPE_IVEC2:
+ case VertexInputTest::GLSL_TYPE_IVEC3:
+ case VertexInputTest::GLSL_TYPE_IVEC4:
+ writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, -(vertexInputIndex + swizzledNdx));
+ break;
+
+ case VertexInputTest::GLSL_TYPE_UINT:
+ case VertexInputTest::GLSL_TYPE_UVEC2:
+ case VertexInputTest::GLSL_TYPE_UVEC3:
+ case VertexInputTest::GLSL_TYPE_UVEC4:
+ writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx, vertexInputIndex + swizzledNdx);
+ break;
+
+ case VertexInputTest::GLSL_TYPE_FLOAT:
+ case VertexInputTest::GLSL_TYPE_VEC2:
+ case VertexInputTest::GLSL_TYPE_VEC3:
+ case VertexInputTest::GLSL_TYPE_VEC4:
+ case VertexInputTest::GLSL_TYPE_MAT2:
+ case VertexInputTest::GLSL_TYPE_MAT3:
+ case VertexInputTest::GLSL_TYPE_MAT4:
+ if (isVertexFormatSfloat(attribute.vkDescription.format))
+ {
+ writeVertexInputValueSfloat(destPtr, attribute.vkDescription.format, componentNdx, -(0.01f * (float)(vertexInputIndex + swizzledNdx)));
+ }
+ else if (isVertexFormatSscaled(attribute.vkDescription.format))
+ {
+ writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, -(vertexInputIndex + swizzledNdx));
+ }
+ else if (isVertexFormatUscaled(attribute.vkDescription.format) || isVertexFormatUnorm(attribute.vkDescription.format) || isVertexFormatSRGB(attribute.vkDescription.format))
+ {
+ writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx, vertexInputIndex + swizzledNdx);
+ }
+ else if (isVertexFormatSnorm(attribute.vkDescription.format))
+ {
+ const deInt32 minIntValue = -((1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8 - 1))) + 1;
+ writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, minIntValue + (vertexInputIndex + swizzledNdx));
+ }
+ else
+ DE_ASSERT(false);
+ break;
+
+ case VertexInputTest::GLSL_TYPE_DOUBLE:
+ case VertexInputTest::GLSL_TYPE_DVEC2:
+ case VertexInputTest::GLSL_TYPE_DVEC3:
+ case VertexInputTest::GLSL_TYPE_DVEC4:
+ case VertexInputTest::GLSL_TYPE_DMAT2:
+ case VertexInputTest::GLSL_TYPE_DMAT3:
+ case VertexInputTest::GLSL_TYPE_DMAT4:
+ *(reinterpret_cast<double *>(destPtr) + componentNdx) = -0.01 * (vertexInputIndex + swizzledNdx);
+
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+ }
+}
+
+tcu::TestStatus VertexInputInstance::iterate (void)
+{
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // deUint32 waitSemaphoreCount;
+ DE_NULL, // const VkSemaphore* pWaitSemaphores;
+ 1u, // deUint32 commandBufferCount;
+ &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
+ 0u, // deUint32 signalSemaphoreCount;
+ DE_NULL // const VkSemaphore* pSignalSemaphores;
+ };
+
+ VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+ VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+ VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+ return verifyImage();
+}
+
+bool VertexInputTest::isCompatibleType (VkFormat format, GlslType glslType)
+{
+ const GlslTypeDescription glslTypeDesc = s_glslTypeDescriptions[glslType];
+
+ if ((deUint32)s_glslTypeDescriptions[glslType].vertexInputComponentCount == getVertexFormatComponentCount(format))
+ {
+ switch (glslTypeDesc.basicType)
+ {
+ case GLSL_BASIC_TYPE_INT:
+ return isVertexFormatSint(format);
+
+ case GLSL_BASIC_TYPE_UINT:
+ return isVertexFormatUint(format);
+
+ case GLSL_BASIC_TYPE_FLOAT:
+ return getVertexFormatComponentSize(format) <= 4 && (isVertexFormatSfloat(format) || isVertexFormatSnorm(format) || isVertexFormatUnorm(format) || isVertexFormatSscaled(format) || isVertexFormatUscaled(format) || isVertexFormatSRGB(format));
+
+ case GLSL_BASIC_TYPE_DOUBLE:
+ return isVertexFormatSfloat(format) && getVertexFormatComponentSize(format) == 8;
+
+ default:
+ DE_ASSERT(false);
+ return false;
+ }
+ }
+ else
+ return false;
+}
+
+tcu::TestStatus VertexInputInstance::verifyImage (void)
+{
+ bool compareOk = false;
+ const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
+ tcu::TextureLevel reference (tcuColorFormat, m_renderSize.x(), m_renderSize.y());
+ const tcu::PixelBufferAccess refRedSubregion (tcu::getSubregion(reference.getAccess(),
+ deRoundFloatToInt32((float)m_renderSize.x() * 0.0f),
+ deRoundFloatToInt32((float)m_renderSize.y() * 0.0f),
+ deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+ deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
+ const tcu::PixelBufferAccess refBlueSubregion (tcu::getSubregion(reference.getAccess(),
+ deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+ deRoundFloatToInt32((float)m_renderSize.y() * 0.0f),
+ deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+ deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
+
+ // Create reference image
+ tcu::clear(reference.getAccess(), defaultClearColor(tcuColorFormat));
+ tcu::clear(refRedSubregion, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+ tcu::clear(refBlueSubregion, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Compare result with reference image
+ {
+ const DeviceInterface& vk = m_context.getDeviceInterface();
+ const VkDevice vkDevice = m_context.getDevice();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+ SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+ de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
+
+ compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+ "IntImageCompare",
+ "Image comparison",
+ reference.getAccess(),
+ result->getAccess(),
+ tcu::UVec4(2, 2, 2, 2),
+ tcu::IVec3(1, 1, 0),
+ true,
+ tcu::COMPARE_LOG_RESULT);
+ }
+
+ if (compareOk)
+ return tcu::TestStatus::pass("Result image matches reference");
+ else
+ return tcu::TestStatus::fail("Image mismatch");
+}
+
+std::string getAttributeInfoCaseName (const VertexInputTest::AttributeInfo& attributeInfo)
+{
+ std::ostringstream caseName;
+ const std::string formatName = getFormatName(attributeInfo.vkType);
+
+ caseName << VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].name << "_as_" << de::toLower(formatName.substr(10)) << "_rate_";
+
+ if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+ caseName << "vertex";
+ else
+ caseName << "instance";
+
+ return caseName.str();
+}
+
+std::string getAttributeInfosCaseName (const std::vector<VertexInputTest::AttributeInfo>& attributeInfos)
+{
+ std::ostringstream caseName;
+
+ for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+ {
+ caseName << getAttributeInfoCaseName(attributeInfos[attributeNdx]);
+
+ if (attributeNdx < attributeInfos.size() - 1)
+ caseName << "-";
+ }
+
+ return caseName.str();
+}
+
+std::string getAttributeInfoDescription (const VertexInputTest::AttributeInfo& attributeInfo)
+{
+ std::ostringstream caseDesc;
+
+ caseDesc << std::string(VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].name) << " from type " << getFormatName(attributeInfo.vkType) << " with ";
+
+ if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+ caseDesc << "vertex input rate ";
+ else
+ caseDesc << "instance input rate ";
+
+ return caseDesc.str();
+}
+
+std::string getAttributeInfosDescription (const std::vector<VertexInputTest::AttributeInfo>& attributeInfos)
+{
+ std::ostringstream caseDesc;
+
+ caseDesc << "Uses vertex attributes:\n";
+
+ for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+ caseDesc << "\t- " << getAttributeInfoDescription (attributeInfos[attributeNdx]) << "\n";
+
+ return caseDesc.str();
+}
+
+struct CompatibleFormats
+{
+ VertexInputTest::GlslType glslType;
+ std::vector<VkFormat> compatibleVkFormats;
+};
+
+de::MovePtr<tcu::TestCaseGroup> createSingleAttributeTests (tcu::TestContext& testCtx)
+{
+ const VkFormat vertexFormats[] =
+ {
+ // Required, unpacked
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8_SNORM,
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_R8_SINT,
+ VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_R8G8_SNORM,
+ VK_FORMAT_R8G8_UINT,
+ VK_FORMAT_R8G8_SINT,
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SNORM,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_FORMAT_R8G8B8A8_SINT,
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_R16_UNORM,
+ VK_FORMAT_R16_SNORM,
+ VK_FORMAT_R16_UINT,
+ VK_FORMAT_R16_SINT,
+ VK_FORMAT_R16_SFLOAT,
+ VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_R16G16_SNORM,
+ VK_FORMAT_R16G16_UINT,
+ VK_FORMAT_R16G16_SINT,
+ VK_FORMAT_R16G16_SFLOAT,
+ VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_R16G16B16A16_SNORM,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_FORMAT_R16G16B16A16_SINT,
+ VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_FORMAT_R32_UINT,
+ VK_FORMAT_R32_SINT,
+ VK_FORMAT_R32_SFLOAT,
+ VK_FORMAT_R32G32_UINT,
+ VK_FORMAT_R32G32_SINT,
+ VK_FORMAT_R32G32_SFLOAT,
+ VK_FORMAT_R32G32B32_UINT,
+ VK_FORMAT_R32G32B32_SINT,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ VK_FORMAT_R32G32B32A32_UINT,
+ VK_FORMAT_R32G32B32A32_SINT,
+ VK_FORMAT_R32G32B32A32_SFLOAT,
+
+ // Scaled formats
+ VK_FORMAT_R8G8_USCALED,
+ VK_FORMAT_R8G8_SSCALED,
+ VK_FORMAT_R16_USCALED,
+ VK_FORMAT_R16_SSCALED,
+ VK_FORMAT_R8G8B8_USCALED,
+ VK_FORMAT_R8G8B8_SSCALED,
+ VK_FORMAT_B8G8R8_USCALED,
+ VK_FORMAT_B8G8R8_SSCALED,
+ VK_FORMAT_R8G8B8A8_USCALED,
+ VK_FORMAT_R8G8B8A8_SSCALED,
+ VK_FORMAT_B8G8R8A8_USCALED,
+ VK_FORMAT_B8G8R8A8_SSCALED,
+ VK_FORMAT_R16G16_USCALED,
+ VK_FORMAT_R16G16_SSCALED,
+ VK_FORMAT_R16G16B16_USCALED,
+ VK_FORMAT_R16G16B16_SSCALED,
+ VK_FORMAT_R16G16B16A16_USCALED,
+ VK_FORMAT_R16G16B16A16_SSCALED,
+
+ // SRGB formats
+ VK_FORMAT_R8_SRGB,
+ VK_FORMAT_R8G8_SRGB,
+ VK_FORMAT_R8G8B8_SRGB,
+ VK_FORMAT_B8G8R8_SRGB,
+ VK_FORMAT_R8G8B8A8_SRGB,
+ VK_FORMAT_B8G8R8A8_SRGB,
+
+ // Double formats
+ VK_FORMAT_R64_SFLOAT,
+ VK_FORMAT_R64G64_SFLOAT,
+ VK_FORMAT_R64G64B64_SFLOAT,
+ VK_FORMAT_R64G64B64A64_SFLOAT,
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> singleAttributeTests (new tcu::TestCaseGroup(testCtx, "single_attribute", "Uses one attribute"));
+
+ for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
+ {
+ for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
+ {
+ if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
+ {
+ // Create test case for RATE_VERTEX
+ VertexInputTest::AttributeInfo attributeInfo;
+ attributeInfo.vkType = vertexFormats[formatNdx];
+ attributeInfo.glslType = (VertexInputTest::GlslType)glslTypeNdx;
+ attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ singleAttributeTests->addChild(new VertexInputTest(testCtx,
+ getAttributeInfoCaseName(attributeInfo),
+ getAttributeInfoDescription(attributeInfo),
+ std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
+ VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+
+ // Create test case for RATE_INSTANCE
+ attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
+
+ singleAttributeTests->addChild(new VertexInputTest(testCtx,
+ getAttributeInfoCaseName(attributeInfo),
+ getAttributeInfoDescription(attributeInfo),
+ std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
+ VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+ }
+ }
+ }
+
+ return singleAttributeTests;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createMultipleAttributeTests (tcu::TestContext& testCtx)
+{
+ // Required vertex formats, unpacked
+ const VkFormat vertexFormats[] =
+ {
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8_SNORM,
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_R8_SINT,
+ VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_R8G8_SNORM,
+ VK_FORMAT_R8G8_UINT,
+ VK_FORMAT_R8G8_SINT,
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SNORM,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_FORMAT_R8G8B8A8_SINT,
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_R16_UNORM,
+ VK_FORMAT_R16_SNORM,
+ VK_FORMAT_R16_UINT,
+ VK_FORMAT_R16_SINT,
+ VK_FORMAT_R16_SFLOAT,
+ VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_R16G16_SNORM,
+ VK_FORMAT_R16G16_UINT,
+ VK_FORMAT_R16G16_SINT,
+ VK_FORMAT_R16G16_SFLOAT,
+ VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_R16G16B16A16_SNORM,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_FORMAT_R16G16B16A16_SINT,
+ VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_FORMAT_R32_UINT,
+ VK_FORMAT_R32_SINT,
+ VK_FORMAT_R32_SFLOAT,
+ VK_FORMAT_R32G32_UINT,
+ VK_FORMAT_R32G32_SINT,
+ VK_FORMAT_R32G32_SFLOAT,
+ VK_FORMAT_R32G32B32_UINT,
+ VK_FORMAT_R32G32B32_SINT,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ VK_FORMAT_R32G32B32A32_UINT,
+ VK_FORMAT_R32G32B32A32_SINT,
+ VK_FORMAT_R32G32B32A32_SFLOAT
+ };
+
+ de::MovePtr<tcu::TestCaseGroup> multipleAttributeTests (new tcu::TestCaseGroup(testCtx, "multiple_attributes", "Uses more than one attribute"));
+
+ // Find compatible VK formats for each GLSL vertex type
+ CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
+ {
+ for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
+ {
+ for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
+ {
+ if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
+ compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
+ }
+ }
+ }
+
+ de::Random randomFunc (102030);
+ GlslTypeCombinationsIterator glslTypeCombinationsItr (VertexInputTest::GLSL_TYPE_DOUBLE, 3); // Exclude double values, which are not included in vertexFormats
+ de::MovePtr<tcu::TestCaseGroup> oneToOneAttributeTests (new tcu::TestCaseGroup(testCtx, "attributes", ""));
+ de::MovePtr<tcu::TestCaseGroup> oneToManyAttributeTests (new tcu::TestCaseGroup(testCtx, "attributes", ""));
+
+ while (glslTypeCombinationsItr.hasNext())
+ {
+ const std::vector<VertexInputTest::GlslType> glslTypes = glslTypeCombinationsItr.next();
+ std::vector<VertexInputTest::AttributeInfo> attributeInfos (glslTypes.size());
+
+ for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+ {
+ DE_ASSERT(!compatibleFormats[glslTypes[attributeNdx]].compatibleVkFormats.empty());
+
+ // Select a random compatible format
+ const std::vector<VkFormat>& formats = compatibleFormats[glslTypes[attributeNdx]].compatibleVkFormats;
+ const VkFormat format = formats[randomFunc.getUint32() % formats.size()];
+
+ attributeInfos[attributeNdx].glslType = glslTypes[attributeNdx];
+ attributeInfos[attributeNdx].inputRate = (attributeNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+ attributeInfos[attributeNdx].vkType = format;
+ }
+
+ const std::string caseName = getAttributeInfosCaseName(attributeInfos);
+ const std::string caseDesc = getAttributeInfosDescription(attributeInfos);
+
+ oneToOneAttributeTests->addChild(new VertexInputTest(testCtx, caseName, caseDesc, attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+ oneToManyAttributeTests->addChild(new VertexInputTest(testCtx, caseName, caseDesc, attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY));
+ }
+
+ de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests (new tcu::TestCaseGroup(testCtx, "binding_one_to_one", "Each attribute uses a unique binding"));
+ bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
+ multipleAttributeTests->addChild(bindingOneToOneTests.release());
+
+ de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests (new tcu::TestCaseGroup(testCtx, "binding_one_to_many", "Attributes share the same binding"));
+ bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
+ multipleAttributeTests->addChild(bindingOneToManyTests.release());
+
+ return multipleAttributeTests;
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createVertexInputTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> vertexInputTests (new tcu::TestCaseGroup(testCtx, "vertex_input", ""));
+
+ vertexInputTests->addChild(createSingleAttributeTests(testCtx).release());
+ vertexInputTests->addChild(createMultipleAttributeTests(testCtx).release());
+
+ return vertexInputTests.release();
+}
+
+} // pipeline
+} // vkt
--- /dev/null
+#ifndef _VKTPIPELINEVERTEXINPUTTESTS_HPP
+#define _VKTPIPELINEVERTEXINPUTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vertex Input Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createVertexInputTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEVERTEXINPUTTESTS_HPP
*//*--------------------------------------------------------------------*/
#include "vktPipelineVertexUtil.hpp"
+#include "vkStrUtil.hpp"
#include "tcuVectorUtil.hpp"
+#include "deStringUtil.hpp"
namespace vkt
{
namespace pipeline
{
+using namespace vk;
+
+deUint32 getVertexFormatSize (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R8_SNORM:
+ case VK_FORMAT_R8_USCALED:
+ case VK_FORMAT_R8_SSCALED:
+ case VK_FORMAT_R8_UINT:
+ case VK_FORMAT_R8_SINT:
+ case VK_FORMAT_R8_SRGB:
+ case VK_FORMAT_R4G4_UNORM_PACK8:
+ return 1;
+
+ case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_R8G8_SNORM:
+ case VK_FORMAT_R8G8_USCALED:
+ case VK_FORMAT_R8G8_SSCALED:
+ case VK_FORMAT_R8G8_UINT:
+ case VK_FORMAT_R8G8_SINT:
+ case VK_FORMAT_R8G8_SRGB:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R16_USCALED:
+ case VK_FORMAT_R16_SSCALED:
+ case VK_FORMAT_R16_UINT:
+ case VK_FORMAT_R16_SINT:
+ case VK_FORMAT_R16_SFLOAT:
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+ return 2;
+
+ case VK_FORMAT_R8G8B8_UNORM:
+ case VK_FORMAT_R8G8B8_SNORM:
+ case VK_FORMAT_R8G8B8_USCALED:
+ case VK_FORMAT_R8G8B8_SSCALED:
+ case VK_FORMAT_R8G8B8_UINT:
+ case VK_FORMAT_R8G8B8_SINT:
+ case VK_FORMAT_R8G8B8_SRGB:
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_B8G8R8_SNORM:
+ case VK_FORMAT_B8G8R8_USCALED:
+ case VK_FORMAT_B8G8R8_SSCALED:
+ case VK_FORMAT_B8G8R8_UINT:
+ case VK_FORMAT_B8G8R8_SINT:
+ case VK_FORMAT_B8G8R8_SRGB:
+ return 3;
+
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SNORM:
+ case VK_FORMAT_R8G8B8A8_USCALED:
+ case VK_FORMAT_R8G8B8A8_SSCALED:
+ case VK_FORMAT_R8G8B8A8_UINT:
+ case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+ case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+ case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+ case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+ case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
+ case VK_FORMAT_R16G16_USCALED:
+ case VK_FORMAT_R16G16_SSCALED:
+ case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R16G16_SINT:
+ case VK_FORMAT_R16G16_SFLOAT:
+ case VK_FORMAT_R32_UINT:
+ case VK_FORMAT_R32_SINT:
+ case VK_FORMAT_R32_SFLOAT:
+ case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+ case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_B8G8R8A8_UINT:
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+ case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+ return 4;
+
+ case VK_FORMAT_R16G16B16_UNORM:
+ case VK_FORMAT_R16G16B16_SNORM:
+ case VK_FORMAT_R16G16B16_USCALED:
+ case VK_FORMAT_R16G16B16_SSCALED:
+ case VK_FORMAT_R16G16B16_UINT:
+ case VK_FORMAT_R16G16B16_SINT:
+ case VK_FORMAT_R16G16B16_SFLOAT:
+ return 6;
+
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ case VK_FORMAT_R16G16B16A16_USCALED:
+ case VK_FORMAT_R16G16B16A16_SSCALED:
+ case VK_FORMAT_R16G16B16A16_UINT:
+ case VK_FORMAT_R16G16B16A16_SINT:
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ case VK_FORMAT_R32G32_UINT:
+ case VK_FORMAT_R32G32_SINT:
+ case VK_FORMAT_R32G32_SFLOAT:
+ case VK_FORMAT_R64_SFLOAT:
+ return 8;
+
+ case VK_FORMAT_R32G32B32_UINT:
+ case VK_FORMAT_R32G32B32_SINT:
+ case VK_FORMAT_R32G32B32_SFLOAT:
+ return 12;
+
+ case VK_FORMAT_R32G32B32A32_UINT:
+ case VK_FORMAT_R32G32B32A32_SINT:
+ case VK_FORMAT_R32G32B32A32_SFLOAT:
+ case VK_FORMAT_R64G64_SFLOAT:
+ return 16;
+
+ case VK_FORMAT_R64G64B64_SFLOAT:
+ return 24;
+
+ case VK_FORMAT_R64G64B64A64_SFLOAT:
+ return 32;
+
+ default:
+ break;
+ }
+
+ DE_ASSERT(false);
+ return 0;
+}
+
+deUint32 getVertexFormatComponentCount (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_USCALED:
+ case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R8_UINT:
+ case VK_FORMAT_R8_SSCALED:
+ case VK_FORMAT_R8_SRGB:
+ case VK_FORMAT_R8_SNORM:
+ case VK_FORMAT_R8_SINT:
+ case VK_FORMAT_R16_USCALED:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_UINT:
+ case VK_FORMAT_R16_SSCALED:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R16_SINT:
+ case VK_FORMAT_R16_SFLOAT:
+ case VK_FORMAT_R32_UINT:
+ case VK_FORMAT_R32_SINT:
+ case VK_FORMAT_R32_SFLOAT:
+ case VK_FORMAT_R64_SFLOAT:
+ return 1;
+
+ case VK_FORMAT_R4G4_UNORM_PACK8:
+ case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_R8G8_SNORM:
+ case VK_FORMAT_R8G8_USCALED:
+ case VK_FORMAT_R8G8_SSCALED:
+ case VK_FORMAT_R8G8_UINT:
+ case VK_FORMAT_R8G8_SINT:
+ case VK_FORMAT_R8G8_SRGB:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
+ case VK_FORMAT_R16G16_USCALED:
+ case VK_FORMAT_R16G16_SSCALED:
+ case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R16G16_SINT:
+ case VK_FORMAT_R16G16_SFLOAT:
+ case VK_FORMAT_R32G32_UINT:
+ case VK_FORMAT_R32G32_SINT:
+ case VK_FORMAT_R32G32_SFLOAT:
+ case VK_FORMAT_R64G64_SFLOAT:
+ return 2;
+
+ case VK_FORMAT_R8G8B8_UNORM:
+ case VK_FORMAT_R8G8B8_SNORM:
+ case VK_FORMAT_R8G8B8_USCALED:
+ case VK_FORMAT_R8G8B8_SSCALED:
+ case VK_FORMAT_R8G8B8_UINT:
+ case VK_FORMAT_R8G8B8_SINT:
+ case VK_FORMAT_R8G8B8_SRGB:
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_B8G8R8_SNORM:
+ case VK_FORMAT_B8G8R8_USCALED:
+ case VK_FORMAT_B8G8R8_SSCALED:
+ case VK_FORMAT_B8G8R8_UINT:
+ case VK_FORMAT_B8G8R8_SINT:
+ case VK_FORMAT_B8G8R8_SRGB:
+ case VK_FORMAT_R16G16B16_UNORM:
+ case VK_FORMAT_R16G16B16_SNORM:
+ case VK_FORMAT_R16G16B16_USCALED:
+ case VK_FORMAT_R16G16B16_SSCALED:
+ case VK_FORMAT_R16G16B16_UINT:
+ case VK_FORMAT_R16G16B16_SINT:
+ case VK_FORMAT_R16G16B16_SFLOAT:
+ case VK_FORMAT_R32G32B32_UINT:
+ case VK_FORMAT_R32G32B32_SINT:
+ case VK_FORMAT_R32G32B32_SFLOAT:
+ case VK_FORMAT_R64G64B64_SFLOAT:
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+ case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+ return 3;
+
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SNORM:
+ case VK_FORMAT_R8G8B8A8_USCALED:
+ case VK_FORMAT_R8G8B8A8_SSCALED:
+ case VK_FORMAT_R8G8B8A8_UINT:
+ case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_B8G8R8A8_UINT:
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ case VK_FORMAT_R16G16B16A16_USCALED:
+ case VK_FORMAT_R16G16B16A16_SSCALED:
+ case VK_FORMAT_R16G16B16A16_UINT:
+ case VK_FORMAT_R16G16B16A16_SINT:
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ case VK_FORMAT_R32G32B32A32_UINT:
+ case VK_FORMAT_R32G32B32A32_SINT:
+ case VK_FORMAT_R32G32B32A32_SFLOAT:
+ case VK_FORMAT_R64G64B64A64_SFLOAT:
+ case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+ case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+ case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+ case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+ case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+ case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+ return 4;
+
+ default:
+ break;
+ }
+
+ DE_ASSERT(false);
+ return 0;
+}
+
+deUint32 getVertexFormatComponentSize (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R8_SNORM:
+ case VK_FORMAT_R8_USCALED:
+ case VK_FORMAT_R8_SSCALED:
+ case VK_FORMAT_R8_UINT:
+ case VK_FORMAT_R8_SINT:
+ case VK_FORMAT_R8_SRGB:
+ case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_R8G8_SNORM:
+ case VK_FORMAT_R8G8_USCALED:
+ case VK_FORMAT_R8G8_SSCALED:
+ case VK_FORMAT_R8G8_UINT:
+ case VK_FORMAT_R8G8_SINT:
+ case VK_FORMAT_R8G8_SRGB:
+ case VK_FORMAT_R8G8B8_UNORM:
+ case VK_FORMAT_R8G8B8_SNORM:
+ case VK_FORMAT_R8G8B8_USCALED:
+ case VK_FORMAT_R8G8B8_SSCALED:
+ case VK_FORMAT_R8G8B8_UINT:
+ case VK_FORMAT_R8G8B8_SINT:
+ case VK_FORMAT_R8G8B8_SRGB:
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_B8G8R8_SNORM:
+ case VK_FORMAT_B8G8R8_USCALED:
+ case VK_FORMAT_B8G8R8_SSCALED:
+ case VK_FORMAT_B8G8R8_UINT:
+ case VK_FORMAT_B8G8R8_SINT:
+ case VK_FORMAT_B8G8R8_SRGB:
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SNORM:
+ case VK_FORMAT_R8G8B8A8_USCALED:
+ case VK_FORMAT_R8G8B8A8_SSCALED:
+ case VK_FORMAT_R8G8B8A8_UINT:
+ case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_B8G8R8A8_UINT:
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ return 1;
+
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R16_USCALED:
+ case VK_FORMAT_R16_SSCALED:
+ case VK_FORMAT_R16_UINT:
+ case VK_FORMAT_R16_SINT:
+ case VK_FORMAT_R16_SFLOAT:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R16G16_SNORM:
+ case VK_FORMAT_R16G16_USCALED:
+ case VK_FORMAT_R16G16_SSCALED:
+ case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R16G16_SINT:
+ case VK_FORMAT_R16G16_SFLOAT:
+ case VK_FORMAT_R16G16B16_UNORM:
+ case VK_FORMAT_R16G16B16_SNORM:
+ case VK_FORMAT_R16G16B16_USCALED:
+ case VK_FORMAT_R16G16B16_SSCALED:
+ case VK_FORMAT_R16G16B16_UINT:
+ case VK_FORMAT_R16G16B16_SINT:
+ case VK_FORMAT_R16G16B16_SFLOAT:
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ case VK_FORMAT_R16G16B16A16_USCALED:
+ case VK_FORMAT_R16G16B16A16_SSCALED:
+ case VK_FORMAT_R16G16B16A16_UINT:
+ case VK_FORMAT_R16G16B16A16_SINT:
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ return 2;
+
+ case VK_FORMAT_R32_UINT:
+ case VK_FORMAT_R32_SINT:
+ case VK_FORMAT_R32_SFLOAT:
+ case VK_FORMAT_R32G32_UINT:
+ case VK_FORMAT_R32G32_SINT:
+ case VK_FORMAT_R32G32_SFLOAT:
+ case VK_FORMAT_R32G32B32_UINT:
+ case VK_FORMAT_R32G32B32_SINT:
+ case VK_FORMAT_R32G32B32_SFLOAT:
+ case VK_FORMAT_R32G32B32A32_UINT:
+ case VK_FORMAT_R32G32B32A32_SINT:
+ case VK_FORMAT_R32G32B32A32_SFLOAT:
+ return 4;
+
+ case VK_FORMAT_R64_SFLOAT:
+ case VK_FORMAT_R64G64_SFLOAT:
+ case VK_FORMAT_R64G64B64_SFLOAT:
+ case VK_FORMAT_R64G64B64A64_SFLOAT:
+ return 8;
+
+ default:
+ break;
+ }
+
+ DE_ASSERT(false);
+ return 0;
+}
+
+bool isVertexFormatComponentOrderBGR (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_B8G8R8_SNORM:
+ case VK_FORMAT_B8G8R8_USCALED:
+ case VK_FORMAT_B8G8R8_SSCALED:
+ case VK_FORMAT_B8G8R8_UINT:
+ case VK_FORMAT_B8G8R8_SINT:
+ case VK_FORMAT_B8G8R8_SRGB:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_B8G8R8A8_UINT:
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+ case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+ case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool isVertexFormatSint (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_SINT:
+ case VK_FORMAT_R8G8_SINT:
+ case VK_FORMAT_R16_SINT:
+ case VK_FORMAT_R8G8B8_SINT:
+ case VK_FORMAT_B8G8R8_SINT:
+ case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_R16G16_SINT:
+ case VK_FORMAT_R32_SINT:
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+ case VK_FORMAT_R16G16B16_SINT:
+ case VK_FORMAT_R16G16B16A16_SINT:
+ case VK_FORMAT_R32G32_SINT:
+ case VK_FORMAT_R32G32B32_SINT:
+ case VK_FORMAT_R32G32B32A32_SINT:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool isVertexFormatUint (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_UINT:
+ case VK_FORMAT_R8G8_UINT:
+ case VK_FORMAT_R16_UINT:
+ case VK_FORMAT_R8G8B8_UINT:
+ case VK_FORMAT_B8G8R8_UINT:
+ case VK_FORMAT_R8G8B8A8_UINT:
+ case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+ case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R32_UINT:
+ case VK_FORMAT_B8G8R8A8_UINT:
+ case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+ case VK_FORMAT_R16G16B16_UINT:
+ case VK_FORMAT_R16G16B16A16_UINT:
+ case VK_FORMAT_R32G32_UINT:
+ case VK_FORMAT_R32G32B32_UINT:
+ case VK_FORMAT_R32G32B32A32_UINT:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatSfloat (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R16_SFLOAT:
+ case VK_FORMAT_R16G16_SFLOAT:
+ case VK_FORMAT_R32_SFLOAT:
+ case VK_FORMAT_R16G16B16_SFLOAT:
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ case VK_FORMAT_R32G32_SFLOAT:
+ case VK_FORMAT_R64_SFLOAT:
+ case VK_FORMAT_R32G32B32_SFLOAT:
+ case VK_FORMAT_R32G32B32A32_SFLOAT:
+ case VK_FORMAT_R64G64_SFLOAT:
+ case VK_FORMAT_R64G64B64_SFLOAT:
+ case VK_FORMAT_R64G64B64A64_SFLOAT:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatUfloat (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+ case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatUnorm (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R4G4_UNORM_PACK8:
+ case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+ case VK_FORMAT_R8G8B8_UNORM:
+ case VK_FORMAT_B8G8R8_UNORM:
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+ case VK_FORMAT_R16G16B16_UNORM:
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatSnorm (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_SNORM:
+ case VK_FORMAT_R8G8_SNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R8G8B8_SNORM:
+ case VK_FORMAT_B8G8R8_SNORM:
+ case VK_FORMAT_R8G8B8A8_SNORM:
+ case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+ case VK_FORMAT_R16G16_SNORM:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+ case VK_FORMAT_R16G16B16_SNORM:
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatSRGB (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_SRGB:
+ case VK_FORMAT_R8G8_SRGB:
+ case VK_FORMAT_R8G8B8_SRGB:
+ case VK_FORMAT_B8G8R8_SRGB:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatSscaled (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_SSCALED:
+ case VK_FORMAT_R8G8_SSCALED:
+ case VK_FORMAT_R16_SSCALED:
+ case VK_FORMAT_R8G8B8_SSCALED:
+ case VK_FORMAT_B8G8R8_SSCALED:
+ case VK_FORMAT_R8G8B8A8_SSCALED:
+ case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+ case VK_FORMAT_R16G16_SSCALED:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+ case VK_FORMAT_R16G16B16_SSCALED:
+ case VK_FORMAT_R16G16B16A16_SSCALED:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
+bool isVertexFormatUscaled (VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_USCALED:
+ case VK_FORMAT_R8G8_USCALED:
+ case VK_FORMAT_R16_USCALED:
+ case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
+ case VK_FORMAT_R8G8B8_USCALED:
+ case VK_FORMAT_B8G8R8_USCALED:
+ case VK_FORMAT_R8G8B8A8_USCALED:
+ case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+ case VK_FORMAT_R16G16_USCALED:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+ case VK_FORMAT_R16G16B16_USCALED:
+ case VK_FORMAT_R16G16B16A16_USCALED:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+
+}
+
std::vector<Vertex4RGBA> createOverlappingQuads (void)
{
using tcu::Vec2;
tcu::Vec4 texCoord;
};
+deUint32 getVertexFormatSize (vk::VkFormat format);
+deUint32 getVertexFormatComponentCount (vk::VkFormat format);
+deUint32 getVertexFormatComponentSize (vk::VkFormat format);
+bool isVertexFormatComponentOrderBGR (vk::VkFormat format);
+bool isVertexFormatSint (vk::VkFormat format);
+bool isVertexFormatUint (vk::VkFormat format);
+bool isVertexFormatSfloat (vk::VkFormat format);
+bool isVertexFormatUfloat (vk::VkFormat format);
+bool isVertexFormatUnorm (vk::VkFormat format);
+bool isVertexFormatSnorm (vk::VkFormat format);
+bool isVertexFormatSRGB (vk::VkFormat format);
+bool isVertexFormatSscaled (vk::VkFormat format);
+bool isVertexFormatUscaled (vk::VkFormat format);
+
/*! \brief Creates a pattern of 4 overlapping quads.
*
* The quads are alined along the plane Z = 0, with X,Y taking values between -1 and 1.
const CaseContext caseCtx,
ShaderExecutor& executor,
const Variables<In, Out> variables,
- const Inputs<In> inputs,
+ const Samplings<In>& samplings,
const StatementP stmt)
: TestInstance (context)
, m_caseCtx (caseCtx)
, m_executor (executor)
, m_variables (variables)
- , m_inputs (inputs)
+ , m_samplings (samplings)
, m_stmt (stmt)
{
}
CaseContext m_caseCtx;
ShaderExecutor& m_executor;
Variables<In, Out> m_variables;
- Inputs<In> m_inputs;
+ const Samplings<In>& m_samplings;
StatementP m_stmt;
};
typedef typename Out::Out0 Out0;
typedef typename Out::Out1 Out1;
+ Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
const FloatFormat& fmt = m_caseCtx.floatFormat;
const int inCount = numInputs<In>();
const int outCount = numOutputs<Out>();
- const size_t numValues = (inCount > 0) ? m_inputs.in0.size() : 1;
+ const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
Outputs<Out> outputs (numValues);
const FloatFormat highpFmt = m_caseCtx.highpFormat;
const int maxMsgs = 100;
const void* inputArr[] =
{
- &m_inputs.in0.front(), &m_inputs.in1.front(), &m_inputs.in2.front(), &m_inputs.in3.front(),
+ &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
};
void* outputArr[] =
{
&outputs.out0.front(), &outputs.out1.front(),
};
+ switch (inCount)
+ {
+ case 4: DE_ASSERT(inputs.in3.size() == numValues);
+ case 3: DE_ASSERT(inputs.in2.size() == numValues);
+ case 2: DE_ASSERT(inputs.in1.size() == numValues);
+ case 1: DE_ASSERT(inputs.in0.size() == numValues);
+ default: break;
+ }
+
m_executor.execute(m_context, int(numValues), inputArr, outputArr);
// Initialize environment with dummy values so we don't need to bind in inner loop.
typename Traits<Out0>::IVal reference0;
typename Traits<Out1>::IVal reference1;
- env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, m_inputs.in0[valueNdx]));
- env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, m_inputs.in1[valueNdx]));
- env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, m_inputs.in2[valueNdx]));
- env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, m_inputs.in3[valueNdx]));
+ env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
+ env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
+ env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
+ env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
{
EvalContext ctx (fmt, m_caseCtx.precision, env);
if (inCount > 0)
{
builder << "\t" << m_variables.in0->getName() << " = "
- << valueToString(highpFmt, m_inputs.in0[valueNdx]) << "\n";
+ << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
}
if (inCount > 1)
{
builder << "\t" << m_variables.in1->getName() << " = "
- << valueToString(highpFmt, m_inputs.in1[valueNdx]) << "\n";
+ << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
}
if (inCount > 2)
{
builder << "\t" << m_variables.in2->getName() << " = "
- << valueToString(highpFmt, m_inputs.in2[valueNdx]) << "\n";
+ << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
}
if (inCount > 3)
{
builder << "\t" << m_variables.in3->getName() << " = "
- << valueToString(highpFmt, m_inputs.in3[valueNdx]) << "\n";
+ << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
}
if (outCount > 0)
PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
: TestCase (context.testContext, name.c_str(), name.c_str())
, m_ctx (context)
- , m_rnd (0xdeadbeefu + context.testContext.getCommandLine().getBaseSeed())
, m_extension (extension)
, m_executor (DE_NULL)
{
TestLog& log (void) const { return m_testCtx.getLog(); }
template <typename In, typename Out>
- void testStatement (const Variables<In, Out>& variables, const Inputs<In>& inputs, const Statement& stmt);
+ void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
template<typename T>
Symbol makeSymbol (const Variable<T>& variable)
}
CaseContext m_ctx;
- Random m_rnd;
const string m_extension;
ShaderSpec m_spec;
de::MovePtr<ShaderExecutor> m_executor;
};
template <typename In, typename Out>
-void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Inputs<In>& inputs, const Statement& stmt)
+void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
{
const int inCount = numInputs<In>();
const int outCount = numOutputs<Out>();
- const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
- Outputs<Out> outputs (numValues);
Environment env; // Hoisted out of the inner loop for optimization.
- switch (inCount)
- {
- case 4: DE_ASSERT(inputs.in3.size() == numValues);
- case 3: DE_ASSERT(inputs.in2.size() == numValues);
- case 2: DE_ASSERT(inputs.in1.size() == numValues);
- case 1: DE_ASSERT(inputs.in0.size() == numValues);
- default: break;
- }
-
// Print out the statement and its definitions
log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
{
const FloatFormat& floatFormat,
Precision intPrecision,
size_t numSamples,
- Random& rnd)
+ deUint32 seed)
{
+ Random rnd(seed);
Inputs<In> ret;
Inputs<In> fixedInputs;
set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
virtual TestInstance* createInstance (Context& context) const
{
- return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, m_inputs, m_stmt);
+ return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
}
protected:
void buildTest (void);
- virtual const Samplings<In>& getSamplings (void)
+ virtual const Samplings<In>& getSamplings (void) const
{
return instance<DefaultSamplings<In> >();
}
private:
const CaseFunc& m_func;
Variables<In, Out> m_variables;
- Inputs<In> m_inputs;
};
template <typename Sig>
void FuncCase<Sig>::buildTest (void)
{
- m_inputs = generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd);
-
m_variables.out0 = variable<Ret>("out0");
m_variables.out1 = variable<Void>("out1");
m_variables.in0 = variable<Arg0>("in0");
ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
m_stmt = variableAssignment(m_variables.out0, expr);
- this->testStatement(m_variables, m_inputs, *m_stmt);
+ this->testStatement(m_variables, *m_stmt);
}
}
}
virtual TestInstance* createInstance (Context& context) const
{
- return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, m_inputs, m_stmt);
+ return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
}
protected:
void buildTest (void);
-
- virtual const Samplings<In>& getSamplings (void) { return instance<DefaultSamplings<In> >(); }
+ virtual const Samplings<In>& getSamplings (void) const
+ {
+ return instance<DefaultSamplings<In> >();
+ }
private:
const CaseFunc& m_func;
Variables<In, Out> m_variables;
- Inputs<In> m_inputs;
};
template <typename Sig>
void InOutFuncCase<Sig>::buildTest (void)
{
- m_inputs = generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd);
m_variables.out0 = variable<Ret>("out0");
m_variables.out1 = variable<Arg1>("out1");
ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
m_stmt = variableAssignment(m_variables.out0, expr);
- this->testStatement(m_variables, m_inputs, *m_stmt);
+ this->testStatement(m_variables, *m_stmt);
}
}
de::MovePtr<Allocation> alloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset()));
- deMemcpy(alloc->getHostPtr(), dataPtr, inputSize);
+ deMemcpy(alloc->getHostPtr(), dataPtr, (size_t)inputSize);
flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), inputSize);
m_vertexBuffers.push_back(de::SharedPtr<Unique<VkBuffer> >(new Unique<VkBuffer>(buffer)));
1.0f // float lineWidth;
};
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ VK_FALSE, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable;
+ VK_FALSE // VkBool32 alphaToOneEnable;
+ };
+
const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
- DE_NULL, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
&dynamicStateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
1.0f // float lineWidth;
};
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ VK_FALSE, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable;
+ VK_FALSE // VkBool32 alphaToOneEnable;
+ };
+
const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
VK_FALSE, // VkBool32 blendEnable;
&tessellationStateParams, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
- DE_NULL, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
&dynamicStateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
deMemcpy(alloc->getHostPtr(), dataPtr, size);
flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), size);
- // \todo [2015-10-09 elecro] remove the 'hackPadding' variable if the driver support small uniforms,
- // that is for example one float big uniforms.
- const size_t hackPadding = size < 4 * sizeof(float) ? 3 * sizeof(float) : 0;
-
de::MovePtr<BufferUniform> uniformInfo(new BufferUniform());
uniformInfo->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size + hackPadding);
+ uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size);
uniformInfo->location = bindingLocation;
uniformInfo->buffer = VkBufferSp(new vk::Unique<VkBuffer>(buffer));
uniformInfo->alloc = AllocationSp(alloc.release());
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkFillMode fillMode;
VK_CULL_MODE_NONE, // VkCullMode cullMode;
- VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
false, // VkBool32 depthBiasEnable;
0.0f, // float depthBias;
0.0f, // float depthBiasClamp;
1.0f, // float lineWidth;
};
+ const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkPipelineMultisampleStateCreateFlags flags;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
+ VK_FALSE, // VkBool32 sampleShadingEnable;
+ 0.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable;
+ VK_FALSE // VkBool32 alphaToOneEnable;
+ };
+
const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
false, // VkBool32 blendEnable;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
- DE_NULL, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
&dynamicStateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
}
static const std::string header =
- "#version 140\n"
+ "#version 310 es\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n";
using namespace vk;
using std::vector;
-typedef de::MovePtr<Allocation> AllocationMp;
-typedef de::SharedPtr<Allocation> AllocationSp;
-typedef Unique<VkBuffer> BufferHandleUp;
-typedef de::SharedPtr<BufferHandleUp> BufferHandleSp;
+typedef vkt::SpirVAssembly::AllocationMp AllocationMp;
+typedef vkt::SpirVAssembly::AllocationSp AllocationSp;
+
+typedef Unique<VkBuffer> BufferHandleUp;
+typedef de::SharedPtr<BufferHandleUp> BufferHandleSp;
/*--------------------------------------------------------------------*//*!
* \brief Create storage buffer, allocate and bind memory for the buffer
flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
}
-void clearMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes)
+void fillMemoryWithValue (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes, deUint8 value)
{
void* const hostPtr = destAlloc->getHostPtr();
- deMemset((deUint8*)hostPtr, 0, numBytes);
+ deMemset((deUint8*)hostPtr, value, numBytes);
flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
}
/*--------------------------------------------------------------------*//*!
* \brief Create a compute pipeline based on the given shader
*//*--------------------------------------------------------------------*/
-Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShaderModule shader)
+Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShaderModule shader, const char* entryPoint, const vector<deUint32>& specConstants)
{
+ const deUint32 numSpecConstants = (deUint32)specConstants.size();
+ vector<VkSpecializationMapEntry> entries;
+ VkSpecializationInfo specInfo;
+
+ if (numSpecConstants != 0)
+ {
+ entries.reserve(numSpecConstants);
+
+ for (deUint32 ndx = 0; ndx < numSpecConstants; ++ndx)
+ {
+ entries[ndx].constantID = ndx;
+ entries[ndx].offset = ndx * (deUint32)sizeof(deUint32);
+ entries[ndx].size = sizeof(deUint32);
+ }
+
+ specInfo.mapEntryCount = numSpecConstants;
+ specInfo.pMapEntries = &entries[0];
+ specInfo.dataSize = numSpecConstants * sizeof(deUint32);
+ specInfo.pData = specConstants.data();
+ }
+
const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
DE_NULL, // pNext
- (VkPipelineShaderStageCreateFlags)0,
+ (VkPipelineShaderStageCreateFlags)0, // flags
VK_SHADER_STAGE_COMPUTE_BIT, // stage
- shader, // shader
- "main",
- DE_NULL, // pSpecializationInfo
+ shader, // module
+ entryPoint, // pName
+ (numSpecConstants == 0) ? DE_NULL : &specInfo, // pSpecializationInfo
};
const VkComputePipelineCreateInfo pipelineCreateInfo =
{
const size_t numBytes = output->getNumBytes();
BufferHandleUp* buffer = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
- clearMemory(vkdi, device, &*alloc, numBytes);
+ fillMemoryWithValue(vkdi, device, &*alloc, numBytes, 0xff);
descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
outputBuffers.push_back(BufferHandleSp(buffer));
outputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
const ProgramBinary& binary = m_context.getBinaryCollection().get("compute");
Unique<VkShaderModule> module (createShaderModule(vkdi, device, binary, (VkShaderModuleCreateFlags)0u));
- Unique<VkPipeline> computePipeline (createComputePipeline(vkdi, device, *pipelineLayout, *module));
+ Unique<VkPipeline> computePipeline (createComputePipeline(vkdi, device, *pipelineLayout, *module, m_shaderSpec.entryPoint.c_str(), m_shaderSpec.specConstants));
// Create command buffer and record commands
VK_CHECK(vkdi.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
// Check output.
-
- for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+ if (m_shaderSpec.verifyIO)
{
- const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
- if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
+ if (!(*m_shaderSpec.verifyIO)(m_shaderSpec.inputs, outputAllocs, m_shaderSpec.outputs))
return tcu::TestStatus::fail("Output doesn't match with expected");
}
+ else
+ {
+ for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+ {
+ const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
+ if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
+ return tcu::TestStatus::fail("Output doesn't match with expected");
+ }
+ }
return tcu::TestStatus::pass("Ouput match with expected");
}
#include "deDefs.h"
#include "deSharedPtr.hpp"
#include "tcuVector.hpp"
+#include "vkMemUtil.hpp"
#include <string>
#include <vector>
namespace SpirVAssembly
{
+typedef de::MovePtr<vk::Allocation> AllocationMp;
+typedef de::SharedPtr<vk::Allocation> AllocationSp;
+
/*--------------------------------------------------------------------*//*!
* \brief Abstract class for an input/output storage buffer object
*//*--------------------------------------------------------------------*/
std::vector<E> m_elements;
};
-typedef Buffer<float> Float32Buffer;
+DE_STATIC_ASSERT(sizeof(tcu::Vec4) == 4 * sizeof(float));
+
+typedef Buffer<float> Float32Buffer;
+typedef Buffer<deInt32> Int32Buffer;
+typedef Buffer<tcu::Vec4> Vec4Buffer;
/*--------------------------------------------------------------------*//*!
struct ComputeShaderSpec
{
std::string assembly;
+ std::string entryPoint;
std::vector<BufferSp> inputs;
std::vector<BufferSp> outputs;
tcu::IVec3 numWorkGroups;
+ std::vector<deUint32> specConstants;
+ // If null, a default verification will be performed by comparing the memory pointed to by outputAllocations
+ // and the contents of expectedOutputs. Otherwise the function pointed to by verifyIO will be called.
+ // If true is returned, then the test case is assumed to have passed, if false is returned, then the test
+ // case is assumed to have failed.
+ bool (*verifyIO)(const std::vector<BufferSp>& inputs, const std::vector<AllocationSp>& outputAllocations, const std::vector<BufferSp>& expectedOutputs);
+
+ ComputeShaderSpec()
+ : entryPoint ("main")
+ , verifyIO (DE_NULL)
+ {}
+
};
} // SpirVAssembly
#include "deUniquePtr.hpp"
#include "tcuStringTemplate.hpp"
+#include <cmath>
#include "vktSpvAsmComputeShaderCase.hpp"
#include "vktSpvAsmComputeShaderTestUtil.hpp"
#include "vktTestCaseUtil.hpp"
+#include <cmath>
+#include <limits>
#include <map>
#include <string>
#include <sstream>
using tcu::Vec4;
using de::UniquePtr;
using tcu::StringTemplate;
+using tcu::Vec4;
typedef Unique<VkShaderModule> ModuleHandleUp;
typedef de::SharedPtr<ModuleHandleUp> ModuleHandleSp;
template<typename T> T randomScalar (de::Random& rnd, T minValue, T maxValue);
template<> inline float randomScalar (de::Random& rnd, float minValue, float maxValue) { return rnd.getFloat(minValue, maxValue); }
template<> inline deInt32 randomScalar (de::Random& rnd, deInt32 minValue, deInt32 maxValue) { return rnd.getInt(minValue, maxValue); }
-template<> inline deUint32 randomScalar (de::Random& rnd, deUint32 minValue, deUint32 maxValue) { return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
template<typename T>
static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
}
+struct CaseParameter
+{
+ const char* name;
+ string param;
+
+ CaseParameter (const char* case_, const string& param_) : name(case_), param(param_) {}
+};
+
// Assembly code used for testing OpNop, OpConstant{Null|Composite}, Op[No]Line, OpSource[Continued], OpSourceExtension, OpUndef is based on GLSL source code:
//
// #version 430
// }
static const char* const s_ShaderPreamble =
- "OpCapability Shader\n"
- "OpMemoryModel Logical GLSL450\n"
- "OpEntryPoint GLCompute %main \"main\" %id\n"
+ "OpCapability Shader\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint GLCompute %main \"main\" %id\n"
"OpExecutionMode %main LocalSize 1 1 1\n";
static const char* const s_CommonTypes =
// Declares buffer type and layout for uniform variables indata and outdata. Both of them are SSBO bounded to descriptor set 0.
// indata is at binding point 0, while outdata is at 1.
static const char* const s_InputOutputBufferTraits =
- "OpDecorate %inbuf BufferBlock\n"
- "OpDecorate %indata DescriptorSet 0\n"
- "OpDecorate %indata Binding 0\n"
- "OpDecorate %outbuf BufferBlock\n"
- "OpDecorate %outdata DescriptorSet 0\n"
- "OpDecorate %outdata Binding 1\n"
- "OpDecorate %f32arr ArrayStride 4\n"
- "OpMemberDecorate %inbuf 0 Offset 0\n"
+ "OpDecorate %inbuf BufferBlock\n"
+ "OpDecorate %indata DescriptorSet 0\n"
+ "OpDecorate %indata Binding 0\n"
+ "OpDecorate %outbuf BufferBlock\n"
+ "OpDecorate %outdata DescriptorSet 0\n"
+ "OpDecorate %outdata Binding 1\n"
+ "OpDecorate %f32arr ArrayStride 4\n"
+ "OpMemberDecorate %inbuf 0 Offset 0\n"
"OpMemberDecorate %outbuf 0 Offset 0\n";
tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
return group.release();
}
+tcu::TestCaseGroup* createNoContractionGroup (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
+ vector<CaseParameter> cases;
+ const int numElements = 100;
+ vector<float> inputFloats1 (numElements, 0);
+ vector<float> inputFloats2 (numElements, 0);
+ vector<float> outputFloats (numElements, 0);
+ const StringTemplate shaderTemplate (
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ "${DECORATION}\n"
+
+ "OpDecorate %inbuf1 BufferBlock\n"
+ "OpDecorate %indata1 DescriptorSet 0\n"
+ "OpDecorate %indata1 Binding 0\n"
+ "OpDecorate %inbuf2 BufferBlock\n"
+ "OpDecorate %indata2 DescriptorSet 0\n"
+ "OpDecorate %indata2 Binding 1\n"
+ "OpDecorate %outbuf BufferBlock\n"
+ "OpDecorate %outdata DescriptorSet 0\n"
+ "OpDecorate %outdata Binding 2\n"
+ "OpDecorate %f32arr ArrayStride 4\n"
+ "OpMemberDecorate %inbuf1 0 Offset 0\n"
+ "OpMemberDecorate %inbuf2 0 Offset 0\n"
+ "OpMemberDecorate %outbuf 0 Offset 0\n"
+
+ + string(s_CommonTypes) +
+
+ "%inbuf1 = OpTypeStruct %f32arr\n"
+ "%inbufptr1 = OpTypePointer Uniform %inbuf1\n"
+ "%indata1 = OpVariable %inbufptr1 Uniform\n"
+ "%inbuf2 = OpTypeStruct %f32arr\n"
+ "%inbufptr2 = OpTypePointer Uniform %inbuf2\n"
+ "%indata2 = OpVariable %inbufptr2 Uniform\n"
+ "%outbuf = OpTypeStruct %f32arr\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%c_f_m1 = OpConstant %f32 -1.\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc1 = OpAccessChain %f32ptr %indata1 %zero %x\n"
+ "%inval1 = OpLoad %f32 %inloc1\n"
+ "%inloc2 = OpAccessChain %f32ptr %indata2 %zero %x\n"
+ "%inval2 = OpLoad %f32 %inloc2\n"
+ "%mul = OpFMul %f32 %inval1 %inval2\n"
+ "%add = OpFAdd %f32 %mul %c_f_m1\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ " OpStore %outloc %add\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n");
+
+ cases.push_back(CaseParameter("multiplication", "OpDecorate %mul NoContraction"));
+ cases.push_back(CaseParameter("addition", "OpDecorate %add NoContraction"));
+ cases.push_back(CaseParameter("both", "OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"));
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ {
+ inputFloats1[ndx] = 1.f + std::ldexp(1.f, -23); // 1 + 2^-23.
+ inputFloats2[ndx] = 1.f - std::ldexp(1.f, -23); // 1 - 2^-23.
+ // Result for (1 + 2^-23) * (1 - 2^-23) - 1. With NoContraction, the multiplication will be
+ // conducted separately and the result is rounded to 1. So the final result will be 0.f.
+ // If the operation is combined into a precise fused multiply-add, then the result would be
+ // 2^-46 (0xa8800000).
+ outputFloats[ndx] = 0.f;
+ }
+
+ for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+ {
+ map<string, string> specializations;
+ ComputeShaderSpec spec;
+
+ specializations["DECORATION"] = cases[caseNdx].param;
+ spec.assembly = shaderTemplate.specialize(specializations);
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
+ }
+ return group.release();
+}
+
+// Copy contents in the input buffer to the output buffer.
+tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opcopymemory", "Test the OpCopyMemory instruction"));
+ de::Random rnd (deStringHash(group->getName()));
+ const int numElements = 100;
+
+ // The following case adds vec4(0., 0.5, 1.5, 2.5) to each of the elements in the input buffer and writes output to the output buffer.
+ ComputeShaderSpec spec1;
+ vector<Vec4> inputFloats1 (numElements);
+ vector<Vec4> outputFloats1 (numElements);
+
+ fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
+
+ spec1.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%vec4 = OpTypeVector %f32 4\n"
+ "%vec4ptr_u = OpTypePointer Uniform %vec4\n"
+ "%vec4ptr_f = OpTypePointer Function %vec4\n"
+ "%vec4arr = OpTypeRuntimeArray %vec4\n"
+ "%inbuf = OpTypeStruct %vec4arr\n"
+ "%inbufptr = OpTypePointer Uniform %inbuf\n"
+ "%indata = OpVariable %inbufptr Uniform\n"
+ "%outbuf = OpTypeStruct %vec4arr\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%c_f_0 = OpConstant %f32 0.\n"
+ "%c_f_0_5 = OpConstant %f32 0.5\n"
+ "%c_f_1_5 = OpConstant %f32 1.5\n"
+ "%c_f_2_5 = OpConstant %f32 2.5\n"
+ "%c_vec4 = OpConstantComposite %vec4 %c_f_0 %c_f_0_5 %c_f_1_5 %c_f_2_5\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%v_vec4 = OpVariable %vec4ptr_f Function\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %vec4ptr_u %indata %zero %x\n"
+ "%outloc = OpAccessChain %vec4ptr_u %outdata %zero %x\n"
+ " OpCopyMemory %v_vec4 %inloc\n"
+ "%v_vec4_val = OpLoad %vec4 %v_vec4\n"
+ "%add = OpFAdd %vec4 %v_vec4_val %c_vec4\n"
+ " OpStore %outloc %add\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+
+ spec1.inputs.push_back(BufferSp(new Vec4Buffer(inputFloats1)));
+ spec1.outputs.push_back(BufferSp(new Vec4Buffer(outputFloats1)));
+ spec1.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector", "OpCopyMemory elements of vector type", spec1));
+
+ // The following case copies a float[100] variable from the input buffer to the output buffer.
+ ComputeShaderSpec spec2;
+ vector<float> inputFloats2 (numElements);
+ vector<float> outputFloats2 (numElements);
+
+ fillRandomScalars(rnd, -200.f, 200.f, &inputFloats2[0], numElements);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ outputFloats2[ndx] = inputFloats2[ndx];
+
+ spec2.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%hundred = OpConstant %u32 100\n"
+ "%f32arr100 = OpTypeArray %f32 %hundred\n"
+ "%f32arr100ptr_f = OpTypePointer Function %f32arr100\n"
+ "%f32arr100ptr_u = OpTypePointer Uniform %f32arr100\n"
+ "%inbuf = OpTypeStruct %f32arr100\n"
+ "%inbufptr = OpTypePointer Uniform %inbuf\n"
+ "%indata = OpVariable %inbufptr Uniform\n"
+ "%outbuf = OpTypeStruct %f32arr100\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%var = OpVariable %f32arr100ptr_f Function\n"
+ "%inarr = OpAccessChain %f32arr100ptr_u %indata %zero\n"
+ "%outarr = OpAccessChain %f32arr100ptr_u %outdata %zero\n"
+ " OpCopyMemory %var %inarr\n"
+ " OpCopyMemory %outarr %var\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+
+ spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
+ spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+ spec2.numWorkGroups = IVec3(1, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "array", "OpCopyMemory elements of array type", spec2));
+
+ // The following case copies a struct{vec4, vec4, vec4, vec4} variable from the input buffer to the output buffer.
+ ComputeShaderSpec spec3;
+ vector<float> inputFloats3 (16);
+ vector<float> outputFloats3 (16);
+
+ fillRandomScalars(rnd, -200.f, 200.f, &inputFloats3[0], 16);
+
+ for (size_t ndx = 0; ndx < 16; ++ndx)
+ outputFloats3[ndx] = -inputFloats3[ndx];
+
+ spec3.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%vec4 = OpTypeVector %f32 4\n"
+ "%inbuf = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
+ "%inbufptr = OpTypePointer Uniform %inbuf\n"
+ "%indata = OpVariable %inbufptr Uniform\n"
+ "%outbuf = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+ "%vec4stptr = OpTypePointer Function %inbuf\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%var = OpVariable %vec4stptr Function\n"
+ " OpCopyMemory %var %indata\n"
+ " OpCopyMemory %outdata %var\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+
+ spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats3)));
+ spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
+ spec3.numWorkGroups = IVec3(1, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "struct", "OpCopyMemory elements of struct type", spec3));
+
+ // The following case negates multiple float variables from the input buffer and stores the results to the output buffer.
+ ComputeShaderSpec spec4;
+ vector<float> inputFloats4 (numElements);
+ vector<float> outputFloats4 (numElements);
+
+ fillRandomScalars(rnd, -200.f, 200.f, &inputFloats4[0], numElements);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ outputFloats4[ndx] = -inputFloats4[ndx];
+
+ spec4.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%f32ptr_f = OpTypePointer Function %f32\n"
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%var = OpVariable %f32ptr_f Function\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ " OpCopyMemory %var %inloc\n"
+ "%val = OpLoad %f32 %var\n"
+ "%neg = OpFNegate %f32 %val\n"
+ " OpStore %outloc %neg\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+
+ spec4.inputs.push_back(BufferSp(new Float32Buffer(inputFloats4)));
+ spec4.outputs.push_back(BufferSp(new Float32Buffer(outputFloats4)));
+ spec4.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "float", "OpCopyMemory elements of float type", spec4));
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createOpCopyObjectGroup (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opcopyobject", "Test the OpCopyObject instruction"));
+ ComputeShaderSpec spec;
+ de::Random rnd (deStringHash(group->getName()));
+ const int numElements = 100;
+ vector<float> inputFloats (numElements, 0);
+ vector<float> outputFloats (numElements, 0);
+
+ fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ outputFloats[ndx] = inputFloats[ndx] + 7.5f;
+
+ spec.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%fvec3 = OpTypeVector %f32 3\n"
+ "%fmat = OpTypeMatrix %fvec3 3\n"
+ "%three = OpConstant %u32 3\n"
+ "%farr = OpTypeArray %f32 %three\n"
+ "%fst = OpTypeStruct %f32 %f32\n"
+
+ + string(s_InputOutputBuffer) +
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%c_f = OpConstant %f32 1.5\n"
+ "%c_fvec3 = OpConstantComposite %fvec3 %c_f %c_f %c_f\n"
+ "%c_fmat = OpConstantComposite %fmat %c_fvec3 %c_fvec3 %c_fvec3\n"
+ "%c_farr = OpConstantComposite %farr %c_f %c_f %c_f\n"
+ "%c_fst = OpConstantComposite %fst %c_f %c_f\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%c_f_copy = OpCopyObject %f32 %c_f\n"
+ "%c_fvec3_copy = OpCopyObject %fvec3 %c_fvec3\n"
+ "%c_fmat_copy = OpCopyObject %fmat %c_fmat\n"
+ "%c_farr_copy = OpCopyObject %farr %c_farr\n"
+ "%c_fst_copy = OpCopyObject %fst %c_fst\n"
+ "%fvec3_elem = OpCompositeExtract %f32 %c_fvec3_copy 0\n"
+ "%fmat_elem = OpCompositeExtract %f32 %c_fmat_copy 1 2\n"
+ "%farr_elem = OpCompositeExtract %f32 %c_fmat_copy 2\n"
+ "%fst_elem = OpCompositeExtract %f32 %c_fmat_copy 1\n"
+ // Add up. 1.5 * 5 = 7.5.
+ "%add1 = OpFAdd %f32 %c_f_copy %fvec3_elem\n"
+ "%add2 = OpFAdd %f32 %add1 %fmat_elem\n"
+ "%add3 = OpFAdd %f32 %add2 %farr_elem\n"
+ "%add4 = OpFAdd %f32 %add3 %fst_elem\n"
+
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ "%inval = OpLoad %f32 %inloc\n"
+ "%add = OpFAdd %f32 %add4 %inval\n"
+ " OpStore %outloc %add\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "spotcheck", "OpCopyObject on different types", spec));
+
+ return group.release();
+}
// Assembly code used for testing OpUnreachable is based on GLSL source code:
//
// #version 430
return group.release();
}
+struct SpecConstantTwoIntCase
+{
+ const char* caseName;
+ const char* scDefinition0;
+ const char* scDefinition1;
+ const char* scResultType;
+ const char* scOperation;
+ deInt32 scActualValue0;
+ deInt32 scActualValue1;
+ const char* resultOperation;
+ vector<deInt32> expectedOutput;
+
+ SpecConstantTwoIntCase (const char* name,
+ const char* definition0,
+ const char* definition1,
+ const char* resultType,
+ const char* operation,
+ deInt32 value0,
+ deInt32 value1,
+ const char* resultOp,
+ const vector<deInt32>& output)
+ : caseName (name)
+ , scDefinition0 (definition0)
+ , scDefinition1 (definition1)
+ , scResultType (resultType)
+ , scOperation (operation)
+ , scActualValue0 (value0)
+ , scActualValue1 (value1)
+ , resultOperation (resultOp)
+ , expectedOutput (output) {}
+};
+
+tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
+ vector<SpecConstantTwoIntCase> cases;
+ de::Random rnd (deStringHash(group->getName()));
+ const int numElements = 100;
+ vector<deInt32> inputInts (numElements, 0);
+ vector<deInt32> outputInts1 (numElements, 0);
+ vector<deInt32> outputInts2 (numElements, 0);
+ vector<deInt32> outputInts3 (numElements, 0);
+ vector<deInt32> outputInts4 (numElements, 0);
+ vector<deInt32> outputInts5 (numElements, 0);
+ const StringTemplate shaderTemplate (
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+ "OpDecorate %sc_0 SpecId 0\n"
+ "OpDecorate %sc_1 SpecId 1\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%i32ptr = OpTypePointer Uniform %i32\n"
+ "%i32arr = OpTypeRuntimeArray %i32\n"
+ "%boolptr = OpTypePointer Uniform %bool\n"
+ "%boolarr = OpTypeRuntimeArray %bool\n"
+ "%inbuf = OpTypeStruct %i32arr\n"
+ "%inbufptr = OpTypePointer Uniform %inbuf\n"
+ "%indata = OpVariable %inbufptr Uniform\n"
+ "%outbuf = OpTypeStruct %i32arr\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%sc_0 = OpSpecConstant${SC_DEF0}\n"
+ "%sc_1 = OpSpecConstant${SC_DEF1}\n"
+ "%sc_final = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %i32ptr %indata %zero %x\n"
+ "%inval = OpLoad %i32 %inloc\n"
+ "%final = ${GEN_RESULT}\n"
+ "%outloc = OpAccessChain %i32ptr %outdata %zero %x\n"
+ " OpStore %outloc %final\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n");
+
+ fillRandomScalars(rnd, -65536, 65536, &inputInts[0], numElements);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ {
+ outputInts1[ndx] = inputInts[ndx] + 42;
+ outputInts2[ndx] = inputInts[ndx];
+ outputInts3[ndx] = inputInts[ndx] - 11200;
+ outputInts4[ndx] = inputInts[ndx] + 1;
+ outputInts5[ndx] = inputInts[ndx] - 2;
+ }
+
+ const char addScToInput[] = "OpIAdd %i32 %inval %sc_final";
+ const char selectTrueUsingSc[] = "OpSelect %i32 %sc_final %inval %zero";
+ const char selectFalseUsingSc[] = "OpSelect %i32 %sc_final %zero %inval";
+
+ cases.push_back(SpecConstantTwoIntCase("iadd", " %i32 0", " %i32 0", "%i32", "IAdd %sc_0 %sc_1", 62, -20, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("isub", " %i32 0", " %i32 0", "%i32", "ISub %sc_0 %sc_1", 100, 58, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("imul", " %i32 0", " %i32 0", "%i32", "IMul %sc_0 %sc_1", -2, -21, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("sdiv", " %i32 0", " %i32 0", "%i32", "SDiv %sc_0 %sc_1", -126, -3, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("udiv", " %i32 0", " %i32 0", "%i32", "UDiv %sc_0 %sc_1", 126, 3, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("srem", " %i32 0", " %i32 0", "%i32", "SRem %sc_0 %sc_1", 7, -3, addScToInput, outputInts4));
+ cases.push_back(SpecConstantTwoIntCase("smod", " %i32 0", " %i32 0", "%i32", "SMod %sc_0 %sc_1", 7, -3, addScToInput, outputInts5));
+ cases.push_back(SpecConstantTwoIntCase("umod", " %i32 0", " %i32 0", "%i32", "UMod %sc_0 %sc_1", 342, 50, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("bitwiseand", " %i32 0", " %i32 0", "%i32", "BitwiseAnd %sc_0 %sc_1", 42, 63, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("bitwiseor", " %i32 0", " %i32 0", "%i32", "BitwiseOr %sc_0 %sc_1", 34, 8, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("bitwisexor", " %i32 0", " %i32 0", "%i32", "BitwiseAnd %sc_0 %sc_1", 18, 56, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("shiftrightlogical", " %i32 0", " %i32 0", "%i32", "ShiftRightLogical %sc_0 %sc_1", 168, 2, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("shiftrightarithmetic", " %i32 0", " %i32 0", "%i32", "ShiftRightArithmetic %sc_0 %sc_1", 168, 2, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("shiftleftlogical", " %i32 0", " %i32 0", "%i32", "ShiftLeftLogical %sc_0 %sc_1", 21, 1, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("slessthan", " %i32 0", " %i32 0", "%bool", "SLessThan %sc_0 %sc_1", -20, -10, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("ulessthan", " %i32 0", " %i32 0", "%bool", "ULessThan %sc_0 %sc_1", 10, 20, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("sgreaterthan", " %i32 0", " %i32 0", "%bool", "SGreaterThan %sc_0 %sc_1", -1000, 50, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("ugreaterthan", " %i32 0", " %i32 0", "%bool", "UGreaterThan %sc_0 %sc_1", 10, 5, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("slessthanequal", " %i32 0", " %i32 0", "%bool", "SLessThanEqual %sc_0 %sc_1", -10, -10, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("ulessthanequal", " %i32 0", " %i32 0", "%bool", "ULessThanEqual %sc_0 %sc_1", 50, 100, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("sgreaterthanequal", " %i32 0", " %i32 0", "%bool", "SGreaterThanEqual %sc_0 %sc_1", -1000, 50, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("ugreaterthanequal", " %i32 0", " %i32 0", "%bool", "UGreaterThanEqual %sc_0 %sc_1", 10, 10, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("iequal", " %i32 0", " %i32 0", "%bool", "IEqual %sc_0 %sc_1", 42, 24, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("logicaland", "True %bool", "True %bool", "%bool", "LogicalAnd %sc_0 %sc_1", 0, 1, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("logicalor", "False %bool", "False %bool", "%bool", "LogicalOr %sc_0 %sc_1", 1, 0, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("logicalequal", "True %bool", "True %bool", "%bool", "LogicalEqual %sc_0 %sc_1", 0, 1, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("logicalnotequal", "False %bool", "False %bool", "%bool", "LogicalNotEqual %sc_0 %sc_1", 1, 0, selectTrueUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("snegate", " %i32 0", " %i32 0", "%i32", "SNegate %sc_0", -42, 0, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("not", " %i32 0", " %i32 0", "%i32", "Not %sc_0", -43, 0, addScToInput, outputInts1));
+ cases.push_back(SpecConstantTwoIntCase("logicalnot", "False %bool", "False %bool", "%bool", "LogicalNot %sc_0", 1, 0, selectFalseUsingSc, outputInts2));
+ cases.push_back(SpecConstantTwoIntCase("select", "False %bool", " %i32 0", "%i32", "Select %sc_0 %sc_1 %zero", 1, 42, addScToInput, outputInts1));
+ // OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
+
+ for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+ {
+ map<string, string> specializations;
+ ComputeShaderSpec spec;
+
+ specializations["SC_DEF0"] = cases[caseNdx].scDefinition0;
+ specializations["SC_DEF1"] = cases[caseNdx].scDefinition1;
+ specializations["SC_RESULT_TYPE"] = cases[caseNdx].scResultType;
+ specializations["SC_OP"] = cases[caseNdx].scOperation;
+ specializations["GEN_RESULT"] = cases[caseNdx].resultOperation;
+
+ spec.assembly = shaderTemplate.specialize(specializations);
+ spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
+ spec.outputs.push_back(BufferSp(new Int32Buffer(cases[caseNdx].expectedOutput)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+ spec.specConstants.push_back(cases[caseNdx].scActualValue0);
+ spec.specConstants.push_back(cases[caseNdx].scActualValue1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].caseName, cases[caseNdx].caseName, spec));
+ }
+
+ ComputeShaderSpec spec;
+
+ spec.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+ "OpDecorate %sc_0 SpecId 0\n"
+ "OpDecorate %sc_1 SpecId 1\n"
+ "OpDecorate %sc_2 SpecId 2\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+ "%ivec3 = OpTypeVector %i32 3\n"
+ "%i32ptr = OpTypePointer Uniform %i32\n"
+ "%i32arr = OpTypeRuntimeArray %i32\n"
+ "%boolptr = OpTypePointer Uniform %bool\n"
+ "%boolarr = OpTypeRuntimeArray %bool\n"
+ "%inbuf = OpTypeStruct %i32arr\n"
+ "%inbufptr = OpTypePointer Uniform %inbuf\n"
+ "%indata = OpVariable %inbufptr Uniform\n"
+ "%outbuf = OpTypeStruct %i32arr\n"
+ "%outbufptr = OpTypePointer Uniform %outbuf\n"
+ "%outdata = OpVariable %outbufptr Uniform\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%ivec3_0 = OpConstantComposite %ivec3 %zero %zero %zero\n"
+
+ "%sc_0 = OpSpecConstant %i32 0\n"
+ "%sc_1 = OpSpecConstant %i32 0\n"
+ "%sc_2 = OpSpecConstant %i32 0\n"
+ "%sc_vec3_0 = OpSpecConstantOp %ivec3 CompositeInsert %sc_0 %ivec3_0 0\n" // (sc_0, 0, 0)
+ "%sc_vec3_1 = OpSpecConstantOp %ivec3 CompositeInsert %sc_1 %ivec3_0 1\n" // (0, sc_1, 0)
+ "%sc_vec3_2 = OpSpecConstantOp %ivec3 CompositeInsert %sc_2 %ivec3_0 2\n" // (0, 0, sc_2)
+ "%sc_vec3_01 = OpSpecConstantOp %ivec3 VectorShuffle %sc_vec3_0 %sc_vec3_1 1 0 4\n" // (0, sc_0, sc_1)
+ "%sc_vec3_012 = OpSpecConstantOp %ivec3 VectorShuffle %sc_vec3_01 %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
+ "%sc_ext_0 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 0\n" // sc_2
+ "%sc_ext_1 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 1\n" // sc_0
+ "%sc_ext_2 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 2\n" // sc_1
+ "%sc_sub = OpSpecConstantOp %i32 ISub %sc_ext_0 %sc_ext_1\n" // (sc_2 - sc_0)
+ "%sc_final = OpSpecConstantOp %i32 IMul %sc_sub %sc_ext_2\n" // (sc_2 - sc_0) * sc_1
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %i32ptr %indata %zero %x\n"
+ "%inval = OpLoad %i32 %inloc\n"
+ "%final = OpIAdd %i32 %inval %sc_final\n"
+ "%outloc = OpAccessChain %i32ptr %outdata %zero %x\n"
+ " OpStore %outloc %final\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+ spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
+ spec.outputs.push_back(BufferSp(new Int32Buffer(outputInts3)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+ spec.specConstants.push_back(123);
+ spec.specConstants.push_back(56);
+ spec.specConstants.push_back(-77);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector_related", "VectorShuffle, CompositeExtract, & CompositeInsert", spec));
+
+ return group.release();
+}
tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
- ComputeShaderSpec spec;
+ ComputeShaderSpec spec1;
+ ComputeShaderSpec spec2;
+ ComputeShaderSpec spec3;
de::Random rnd (deStringHash(group->getName()));
const int numElements = 100;
vector<float> inputFloats (numElements, 0);
- vector<float> outputFloats (numElements, 0);
+ vector<float> outputFloats1 (numElements, 0);
+ vector<float> outputFloats2 (numElements, 0);
+ vector<float> outputFloats3 (numElements, 0);
fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
{
switch (ndx % 3)
{
- case 0: outputFloats[ndx] = inputFloats[ndx] + 5.5f; break;
- case 1: outputFloats[ndx] = inputFloats[ndx] + 20.5f; break;
- case 2: outputFloats[ndx] = inputFloats[ndx] + 1.75f; break;
+ case 0: outputFloats1[ndx] = inputFloats[ndx] + 5.5f; break;
+ case 1: outputFloats1[ndx] = inputFloats[ndx] + 20.5f; break;
+ case 2: outputFloats1[ndx] = inputFloats[ndx] + 1.75f; break;
default: break;
}
+ outputFloats2[ndx] = inputFloats[ndx] + 6.5f * 3;
+ outputFloats3[ndx] = 8.5f - inputFloats[ndx];
}
- spec.assembly =
+ spec1.assembly =
string(s_ShaderPreamble) +
"OpSource GLSL 430\n"
" OpBranch %phi\n"
" OpFunctionEnd\n";
- spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
- spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
- spec.numWorkGroups = IVec3(numElements, 1, 1);
+ spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
+ spec1.numWorkGroups = IVec3(numElements, 1, 1);
- group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpPhi corner cases", spec));
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "block", "out-of-order and unreachable blocks for OpPhi", spec1));
- return group.release();
-}
+ spec2.assembly =
+ string(s_ShaderPreamble) +
-// Assembly code used for testing block order is based on GLSL source code:
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%one = OpConstant %i32 1\n"
+ "%three = OpConstant %i32 3\n"
+ "%constf6p5 = OpConstant %f32 6.5\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%entry = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ "%inval = OpLoad %f32 %inloc\n"
+ " OpBranch %phi\n"
+
+ "%phi = OpLabel\n"
+ "%step = OpPhi %i32 %zero %entry %step_next %phi\n"
+ "%accum = OpPhi %f32 %inval %entry %accum_next %phi\n"
+ "%step_next = OpIAdd %i32 %step %one\n"
+ "%accum_next = OpFAdd %f32 %accum %constf6p5\n"
+ "%still_loop = OpSLessThan %bool %step %three\n"
+ " OpLoopMerge %exit %phi None\n"
+ " OpBranchConditional %still_loop %phi %exit\n"
+
+ "%exit = OpLabel\n"
+ " OpStore %outloc %accum\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+ spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+ spec2.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "induction", "The usual way induction variables are handled in LLVM IR", spec2));
+
+ spec3.assembly =
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%f32ptr_f = OpTypePointer Function %f32\n"
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%true = OpConstantTrue %bool\n"
+ "%false = OpConstantFalse %bool\n"
+ "%zero = OpConstant %i32 0\n"
+ "%constf8p5 = OpConstant %f32 8.5\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%entry = OpLabel\n"
+ "%b = OpVariable %f32ptr_f Function %constf8p5\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ "%a_init = OpLoad %f32 %inloc\n"
+ "%b_init = OpLoad %f32 %b\n"
+ " OpBranch %phi\n"
+
+ "%phi = OpLabel\n"
+ "%still_loop = OpPhi %bool %true %entry %false %phi\n"
+ "%a_next = OpPhi %f32 %a_init %entry %b_next %phi\n"
+ "%b_next = OpPhi %f32 %b_init %entry %a_next %phi\n"
+ " OpLoopMerge %exit %phi None\n"
+ " OpBranchConditional %still_loop %phi %exit\n"
+
+ "%exit = OpLabel\n"
+ "%sub = OpFSub %f32 %a_next %b_next\n"
+ " OpStore %outloc %sub\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+ spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
+ spec3.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "swap", "Swap the values of two variables using OpPhi", spec3));
+
+ return group.release();
+}
+
+// Assembly code used for testing block order is based on GLSL source code:
//
// #version 430
//
return group.release();
}
-struct CaseParameter
+tcu::TestCaseGroup* createMultipleShaderGroup (tcu::TestContext& testCtx)
{
- const char* name;
- string param;
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multiple_shaders", "Test multiple shaders in the same module"));
+ ComputeShaderSpec spec1;
+ ComputeShaderSpec spec2;
+ de::Random rnd (deStringHash(group->getName()));
+ const int numElements = 100;
+ vector<float> inputFloats (numElements, 0);
+ vector<float> outputFloats1 (numElements, 0);
+ vector<float> outputFloats2 (numElements, 0);
+ fillRandomScalars(rnd, -500.f, 500.f, &inputFloats[0], numElements);
- CaseParameter (const char* case_, const string& param_) : name(case_), param(param_) {}
-};
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ {
+ outputFloats1[ndx] = inputFloats[ndx] + inputFloats[ndx];
+ outputFloats2[ndx] = -inputFloats[ndx];
+ }
+
+ const string assembly =
+ "OpCapability Shader\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint GLCompute %comp_main1 \"entrypoint1\" %id\n"
+ "OpEntryPoint GLCompute %comp_main2 \"entrypoint2\" %id\n"
+ // A module cannot have two OpEntryPoint instructions with the same Execution Model and the same Name string.
+ "OpEntryPoint Vertex %vert_main \"entrypoint2\" %vert_builtins %vertexID %instanceID\n"
+ "OpExecutionMode %main LocalSize 1 1 1\n";
+
+ "OpName %comp_main1 \"entrypoint1\"\n"
+ "OpName %comp_main2 \"entrypoint2\"\n"
+ "OpName %vert_main \"entrypoint2\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+ "OpName %vert_builtin_st \"gl_PerVertex\"\n"
+ "OpName %vertexID \"gl_VertexID\"\n"
+ "OpName %instanceID \"gl_InstanceID\"\n"
+ "OpMemberName %vert_builtin_st 0 \"gl_Position\"\n"
+ "OpMemberName %vert_builtin_st 1 \"gl_PointSize\"\n"
+ "OpMemberName %vert_builtin_st 2 \"gl_ClipDistance\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+ "OpDecorate %vertexID BuiltIn VertexId\n"
+ "OpDecorate %instanceID BuiltIn InstanceId\n"
+ "OpDecorate %vert_builtin_st Block\n"
+ "OpMemberDecorate %vert_builtin_st 0 BuiltIn Position\n"
+ "OpMemberDecorate %vert_builtin_st 1 BuiltIn PointSize\n"
+ "OpMemberDecorate %vert_builtin_st 2 BuiltIn ClipDistance\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%i32ptr = OpTypePointer Input %i32\n"
+ "%vec4 = OpTypeVector %f32 4\n"
+ "%vec4ptr = OpTypePointer Output %vec4\n"
+ "%f32arr1 = OpTypeArray %f32 %one\n"
+ "%vert_builtin_st = OpTypeStruct %vec4 %f32 %f32arr1\n"
+ "%vert_builtin_st_ptr = OpTypePointer Output %vert_builtin_st\n"
+ "%vert_builtins = OpVariable %vert_builtin_st_ptr Output\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%vertexID = OpVariable %i32ptr Input\n"
+ "%instanceID = OpVariable %i32ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%one = OpConstant %u32 1\n"
+ "%c_f32_1 = OpConstant %f32 1\n"
+ "%c_vec4_1 = OpConstantComposite %vec4 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+
+ // gl_Position = vec4(1.);
+ "%vert_main = OpFunction %void None %voidf\n"
+ "%vert_entry = OpLabel\n"
+ "%position = OpAccessChain %vec4ptr %vert_builtins %zero\n"
+ " OpStore %position %c_vec4_1\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n"
+
+ // Double inputs.
+ "%comp_main1 = OpFunction %void None %voidf\n"
+ "%comp1_entry = OpLabel\n"
+ "%idval1 = OpLoad %uvec3 %id\n"
+ "%x1 = OpCompositeExtract %u32 %idval1 0\n"
+ "%inloc1 = OpAccessChain %f32ptr %indata %zero %x1\n"
+ "%inval1 = OpLoad %f32 %inloc1\n"
+ "%add = OpFAdd %f32 %inval1 %inval1\n"
+ "%outloc1 = OpAccessChain %f32ptr %outdata %zero %x1\n"
+ " OpStore %outloc1 %add\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n"
+
+ // Negate inputs.
+ "%comp_main2 = OpFunction %void None %voidf\n"
+ "%comp2_entry = OpLabel\n"
+ "%idval2 = OpLoad %uvec3 %id\n"
+ "%x2 = OpCompositeExtract %u32 %idval2 0\n"
+ "%inloc2 = OpAccessChain %f32ptr %indata %zero %x2\n"
+ "%inval2 = OpLoad %f32 %inloc2\n"
+ "%neg = OpFNegate %f32 %inval2\n"
+ "%outloc2 = OpAccessChain %f32ptr %outdata %zero %x2\n"
+ " OpStore %outloc2 %neg\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n";
+
+ spec1.assembly = assembly;
+ spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
+ spec1.numWorkGroups = IVec3(numElements, 1, 1);
+ spec1.entryPoint = "entrypoint1";
+
+ spec2.assembly = assembly;
+ spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+ spec2.numWorkGroups = IVec3(numElements, 1, 1);
+ spec2.entryPoint = "entrypoint2";
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader1", "multiple shaders in the same module", spec1));
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader2", "multiple shaders in the same module", spec2));
+
+ return group.release();
+}
+
+inline std::string makeLongUTF8String (size_t num4ByteChars)
+{
+ // An example of a longest valid UTF-8 character. Be explicit about the
+ // character type because Microsoft compilers can otherwise interpret the
+ // character string as being over wide (16-bit) characters. Ideally, we
+ // would just use a C++11 UTF-8 string literal, but we want to support older
+ // Microsoft compilers.
+ const std::basic_string<char> earthAfrica("\xF0\x9F\x8C\x8D");
+ std::string longString;
+ longString.reserve(num4ByteChars * 4);
+ for (size_t count = 0; count < num4ByteChars; count++)
+ {
+ longString += earthAfrica;
+ }
+ return longString;
+}
tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
{
cases.push_back(CaseParameter("empty_source_code", "%fname = OpString \"filename\"\n"
"OpSource GLSL 430 %fname \"\""));
cases.push_back(CaseParameter("long_source_code", "%fname = OpString \"filename\"\n"
- "OpSource GLSL 430 %fname \"" + string(65530, 'x') + "\"")); // word count: 65535
+ "OpSource GLSL 430 %fname \"" + makeLongUTF8String(65530) + "ccc\"")); // word count: 65535
cases.push_back(CaseParameter("utf8_source_code", "%fname = OpString \"filename\"\n"
"OpSource GLSL 430 %fname \"\xE2\x98\x82\xE2\x98\x85\"")); // umbrella & black star symbol
cases.push_back(CaseParameter("normal_sourcecontinued", "%fname = OpString \"filename\"\n"
"OpSourceContinued \"\""));
cases.push_back(CaseParameter("long_sourcecontinued", "%fname = OpString \"filename\"\n"
"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
- "OpSourceContinued \"" + string(65533, 'x') + "\"")); // word count: 65535
+ "OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\"")); // word count: 65535
cases.push_back(CaseParameter("utf8_sourcecontinued", "%fname = OpString \"filename\"\n"
"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
"OpSourceContinued \"\xE2\x98\x8E\xE2\x9A\x91\"")); // white telephone & black flag symbol
cases.push_back(CaseParameter("real_extension", "GL_ARB_texture_rectangle"));
cases.push_back(CaseParameter("fake_extension", "GL_ARB_im_the_ultimate_extension"));
cases.push_back(CaseParameter("utf8_extension", "GL_ARB_\xE2\x98\x82\xE2\x98\x85"));
- cases.push_back(CaseParameter("long_extension", string(65533, 'e'))); // word count: 65535
+ cases.push_back(CaseParameter("long_extension", makeLongUTF8String(65533) + "ccc")); // word count: 65535
fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
return group.release();
}
+// Creates a floating point number with the given exponent, and significand
+// bits set. It can only create normalized numbers. Only the least significant
+// 24 bits of the significand will be examined. The final bit of the
+// significand will also be ignored. This allows alignment to be written
+// similarly to C99 hex-floats.
+// For example if you wanted to write 0x1.7f34p-12 you would call
+// constructNormalizedFloat(-12, 0x7f3400)
+float constructNormalizedFloat (deInt32 exponent, deUint32 significand)
+{
+ float f = 1.0f;
+
+ for (deInt32 idx = 0; idx < 23; ++idx)
+ {
+ f += ((significand & 0x800000) == 0) ? 0.f : std::ldexp(1.0f, -idx);
+ significand <<= 1;
+ }
+
+ return std::ldexp(f, exponent);
+}
+
+// Compare instruction for the OpQuantizeF16 compute exact case.
+// Returns true if the output is what is expected from the test case.
+bool compareOpQuantizeF16ComputeExactCase (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs)
+{
+ if (outputAllocs.size() != 1)
+ return false;
+
+ // We really just need this for size because we cannot compare Nans.
+ const BufferSp& expectedOutput = expectedOutputs[0];
+ const float* outputAsFloat = static_cast<const float*>(outputAllocs[0]->getHostPtr());;
+
+ if (expectedOutput->getNumBytes() != 4*sizeof(float)) {
+ return false;
+ }
+
+ if (*outputAsFloat != constructNormalizedFloat(8, 0x304000) &&
+ *outputAsFloat != constructNormalizedFloat(8, 0x300000)) {
+ return false;
+ }
+
+ if (*outputAsFloat != -constructNormalizedFloat(-7, 0x600000) &&
+ *outputAsFloat != -constructNormalizedFloat(-7, 0x604000)) {
+ return false;
+ }
+
+ if (*outputAsFloat != constructNormalizedFloat(2, 0x01C000) &&
+ *outputAsFloat != constructNormalizedFloat(2, 0x020000)) {
+ return false;
+ }
+
+ if (*outputAsFloat != constructNormalizedFloat(1, 0xFFC000) &&
+ *outputAsFloat != constructNormalizedFloat(2, 0x000000)) {
+ return false;
+ }
+
+ return true;
+}
+
+// Checks that every output from a test-case is a float NaN.
+bool compareNan (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs)
+{
+ if (outputAllocs.size() != 1)
+ return false;
+
+ // We really just need this for size because we cannot compare Nans.
+ const BufferSp& expectedOutput = expectedOutputs[0];
+ const float* output_as_float = static_cast<const float*>(outputAllocs[0]->getHostPtr());;
+
+ for (size_t idx = 0; idx < expectedOutput->getNumBytes() / sizeof(float); ++idx)
+ {
+ if (!isnan(output_as_float[idx]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Checks that a compute shader can generate a constant composite value of various types, without exercising a computation on it.
+tcu::TestCaseGroup* createOpQuantizeToF16Group (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opquantize", "Tests the OpQuantizeToF16 instruction"));
+
+ const std::string shader (
+ string(s_ShaderPreamble) +
+
+ "OpSource GLSL 430\n"
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%inval = OpLoad %f32 %inloc\n"
+ "%quant = OpQuantizeToF16 %f32 %inval\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ " OpStore %outloc %quant\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n");
+
+ {
+ ComputeShaderSpec spec;
+ const deUint32 numElements = 100;
+ vector<float> infinities;
+ vector<float> results;
+
+ infinities.reserve(numElements);
+ results.reserve(numElements);
+
+ for (size_t idx = 0; idx < numElements; ++idx)
+ {
+ switch(idx % 4)
+ {
+ case 0:
+ infinities.push_back(std::numeric_limits<float>::infinity());
+ results.push_back(std::numeric_limits<float>::infinity());
+ break;
+ case 1:
+ infinities.push_back(-std::numeric_limits<float>::infinity());
+ results.push_back(-std::numeric_limits<float>::infinity());
+ break;
+ case 2:
+ infinities.push_back(std::ldexp(1.0f, 16));
+ results.push_back(std::numeric_limits<float>::infinity());
+ break;
+ case 3:
+ infinities.push_back(std::ldexp(-1.0f, 32));
+ results.push_back(-std::numeric_limits<float>::infinity());
+ break;
+ }
+ }
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(infinities)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(results)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "infinities", "Check that infinities propagated and created", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ vector<float> nans;
+ const deUint32 numElements = 100;
+
+ nans.reserve(numElements);
+
+ for (size_t idx = 0; idx < numElements; ++idx)
+ {
+ if (idx % 2 == 0)
+ {
+ nans.push_back(std::numeric_limits<float>::quiet_NaN());
+ }
+ else
+ {
+ nans.push_back(-std::numeric_limits<float>::quiet_NaN());
+ }
+ }
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(nans)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(nans)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+ spec.verifyIO = &compareNan;
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "propagated_nans", "Check that nans are propagated", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ vector<float> small;
+ vector<float> zeros;
+ const deUint32 numElements = 100;
+
+ small.reserve(numElements);
+ zeros.reserve(numElements);
+
+ for (size_t idx = 0; idx < numElements; ++idx)
+ {
+ switch(idx % 6)
+ {
+ case 0:
+ small.push_back(0.f);
+ zeros.push_back(0.f);
+ break;
+ case 1:
+ small.push_back(-0.f);
+ zeros.push_back(-0.f);
+ break;
+ case 2:
+ small.push_back(std::ldexp(1.0f, -16));
+ zeros.push_back(0.f);
+ break;
+ case 3:
+ small.push_back(std::ldexp(-1.0f, -32));
+ zeros.push_back(-0.f);
+ break;
+ case 4:
+ small.push_back(std::ldexp(1.0f, -127));
+ zeros.push_back(0.f);
+ break;
+ case 5:
+ small.push_back(-std::ldexp(1.0f, -128));
+ zeros.push_back(-0.f);
+ break;
+ }
+ }
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(small)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(zeros)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ vector<float> exact;
+ const deUint32 numElements = 200;
+
+ exact.reserve(numElements);
+
+ for (size_t idx = 0; idx < numElements; ++idx)
+ exact.push_back(static_cast<float>(idx - 100));
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(exact)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(exact)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ vector<float> inputs;
+ const deUint32 numElements = 4;
+
+ inputs.push_back(constructNormalizedFloat(8, 0x300300));
+ inputs.push_back(-constructNormalizedFloat(-7, 0x600800));
+ inputs.push_back(constructNormalizedFloat(2, 0x01E000));
+ inputs.push_back(constructNormalizedFloat(1, 0xFFE000));
+
+ spec.verifyIO = &compareOpQuantizeF16ComputeExactCase;
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "rounded", "Check that are rounded when needed", spec));
+ }
+
+ return group.release();
+}
+
+// Performs a bitwise copy of source to the destination type Dest.
+template <typename Dest, typename Src>
+Dest bitwiseCast(Src source)
+{
+ Dest dest;
+ DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
+ deMemcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+tcu::TestCaseGroup* createSpecConstantOpQuantizeToF16Group (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opspecconstantop_opquantize", "Tests the OpQuantizeToF16 opcode for the OpSpecConstantOp instruction"));
+ de::Random rnd (deStringHash(group->getName()));
+
+ const std::string shader (
+ string(s_ShaderPreamble) +
+
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ "OpDecorate %sc_0 SpecId 0\n"
+ "OpDecorate %sc_1 SpecId 1\n"
+ "OpDecorate %sc_2 SpecId 2\n"
+ "OpDecorate %sc_3 SpecId 3\n"
+ "OpDecorate %sc_4 SpecId 4\n"
+ "OpDecorate %sc_5 SpecId 5\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+ "%c_u32_6 = OpConstant %u32 6\n"
+
+ "%sc_0 = OpSpecConstant %f32 0.\n"
+ "%sc_1 = OpSpecConstant %f32 0.\n"
+ "%sc_2 = OpSpecConstant %f32 0.\n"
+ "%sc_3 = OpSpecConstant %f32 0.\n"
+ "%sc_4 = OpSpecConstant %f32 0.\n"
+ "%sc_5 = OpSpecConstant %f32 0.\n"
+
+ "%sc_0_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_0\n"
+ "%sc_1_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_1\n"
+ "%sc_2_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_2\n"
+ "%sc_3_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_3\n"
+ "%sc_4_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_4\n"
+ "%sc_5_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_5\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+ "%idval = OpLoad %uvec3 %id\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ "%selector = OpUMod %u32 %x %c_u32_6\n"
+ " OpSelectionMerge %exit None\n"
+ " OpSwitch %selector %exit 0 %case0 1 %case1 2 %case2 3 %case3 4 %case4 5 %case5\n"
+
+ "%case0 = OpLabel\n"
+ " OpStore %outloc %sc_0_quant\n"
+ " OpBranch %exit\n"
+
+ "%case1 = OpLabel\n"
+ " OpStore %outloc %sc_1_quant\n"
+ " OpBranch %exit\n"
+
+ "%case2 = OpLabel\n"
+ " OpStore %outloc %sc_2_quant\n"
+ " OpBranch %exit\n"
+
+ "%case3 = OpLabel\n"
+ " OpStore %outloc %sc_3_quant\n"
+ " OpBranch %exit\n"
+
+ "%case4 = OpLabel\n"
+ " OpStore %outloc %sc_4_quant\n"
+ " OpBranch %exit\n"
+
+ "%case5 = OpLabel\n"
+ " OpStore %outloc %sc_5_quant\n"
+ " OpBranch %exit\n"
+
+ "%exit = OpLabel\n"
+ " OpReturn\n"
+
+ " OpFunctionEnd\n");
+
+ {
+ ComputeShaderSpec spec;
+ const deUint8 numCases = 4;
+ vector<float> inputs (numCases, 0.f);
+ vector<float> outputs;
+
+ spec.numWorkGroups = IVec3(numCases, 1, 1);
+
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::numeric_limits<float>::infinity()));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(-std::numeric_limits<float>::infinity()));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, 16)));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, 32)));
+
+ outputs.push_back(std::numeric_limits<float>::infinity());
+ outputs.push_back(-std::numeric_limits<float>::infinity());
+ outputs.push_back(std::numeric_limits<float>::infinity());
+ outputs.push_back(-std::numeric_limits<float>::infinity());
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "infinities", "Check that infinities propagated and created", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ const deUint8 numCases = 2;
+ vector<float> inputs (numCases, 0.f);
+ vector<float> outputs;
+
+ spec.numWorkGroups = IVec3(numCases, 1, 1);
+ spec.verifyIO = &compareNan;
+
+ outputs.push_back(std::numeric_limits<float>::quiet_NaN());
+ outputs.push_back(-std::numeric_limits<float>::quiet_NaN());
+
+ for (deUint8 idx = 0; idx < numCases; ++idx)
+ spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "propagated_nans", "Check that nans are propagated", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ const deUint8 numCases = 6;
+ vector<float> inputs (numCases, 0.f);
+ vector<float> outputs;
+
+ spec.numWorkGroups = IVec3(numCases, 1, 1);
+
+ spec.specConstants.push_back(bitwiseCast<deUint32>(0.f));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(-0.f));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -16)));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, -32)));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -127)));
+ spec.specConstants.push_back(bitwiseCast<deUint32>(-std::ldexp(1.0f, -128)));
+
+ outputs.push_back(0.f);
+ outputs.push_back(-0.f);
+ outputs.push_back(0.f);
+ outputs.push_back(-0.f);
+ outputs.push_back(0.f);
+ outputs.push_back(-0.f);
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ const deUint8 numCases = 6;
+ vector<float> inputs (numCases, 0.f);
+ vector<float> outputs;
+
+ spec.numWorkGroups = IVec3(numCases, 1, 1);
+
+ for (deUint8 idx = 0; idx < 6; ++idx)
+ {
+ const float f = static_cast<float>(idx * 10 - 30) / 4.f;
+ spec.specConstants.push_back(bitwiseCast<deUint32>(f));
+ outputs.push_back(f);
+ }
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
+ }
+
+ {
+ ComputeShaderSpec spec;
+ const deUint8 numCases = 4;
+ vector<float> inputs (numCases, 0.f);
+ vector<float> outputs;
+
+ spec.numWorkGroups = IVec3(numCases, 1, 1);
+ spec.verifyIO = &compareOpQuantizeF16ComputeExactCase;
+
+ outputs.push_back(constructNormalizedFloat(8, 0x300300));
+ outputs.push_back(-constructNormalizedFloat(-7, 0x600800));
+ outputs.push_back(constructNormalizedFloat(2, 0x01E000));
+ outputs.push_back(constructNormalizedFloat(1, 0xFFE000));
+
+ for (deUint8 idx = 0; idx < numCases; ++idx)
+ spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
+
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+ group->addChild(new SpvAsmComputeShaderCase(
+ testCtx, "rounded", "Check that are rounded when needed", spec));
+ }
+
+ return group.release();
+}
+
// Checks that constant null/composite values can be used in computation.
tcu::TestCaseGroup* createOpConstantUsageGroup (tcu::TestContext& testCtx)
{
return group.release();
}
-// Checks that we can get undefined values for various types, without exercising a computation with it.
-tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
+tcu::TestCaseGroup* createMemoryAccessGroup (tcu::TestContext& testCtx)
{
- de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "memory_access", "Tests memory access cases"));
vector<CaseParameter> cases;
de::Random rnd (deStringHash(group->getName()));
const int numElements = 100;
- vector<float> positiveFloats (numElements, 0);
- vector<float> negativeFloats (numElements, 0);
+ vector<float> inputFloats (numElements, 0);
+ vector<float> outputFloats (numElements, 0);
const StringTemplate shaderTemplate (
string(s_ShaderPreamble) +
+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
- "${TYPE}\n"
+ "%f32ptr_f = OpTypePointer Function %f32\n"
"%id = OpVariable %uvec3ptr Input\n"
"%zero = OpConstant %i32 0\n"
+ "%four = OpConstant %i32 4\n"
"%main = OpFunction %void None %voidf\n"
"%label = OpLabel\n"
+ "%copy = OpVariable %f32ptr_f Function\n"
+ "%idval = OpLoad %uvec3 %id ${ACCESS}\n"
+ "%x = OpCompositeExtract %u32 %idval 0\n"
+ "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
+ "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
+ " OpCopyMemory %copy %inloc ${ACCESS}\n"
+ "%val1 = OpLoad %f32 %copy\n"
+ "%val2 = OpLoad %f32 %inloc\n"
+ "%add = OpFAdd %f32 %val1 %val2\n"
+ " OpStore %outloc %add ${ACCESS}\n"
+ " OpReturn\n"
+ " OpFunctionEnd\n");
- "%undef = OpUndef %type\n"
+ cases.push_back(CaseParameter("null", ""));
+ cases.push_back(CaseParameter("none", "None"));
+ cases.push_back(CaseParameter("volatile", "Volatile"));
+ cases.push_back(CaseParameter("aligned", "Aligned 4"));
+ cases.push_back(CaseParameter("nontemporal", "Nontemporal"));
+ cases.push_back(CaseParameter("aligned_nontemporal", "Aligned|Nontemporal 4"));
+ cases.push_back(CaseParameter("aligned_volatile", "Volatile|Aligned 4"));
+
+ fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
+
+ for (size_t ndx = 0; ndx < numElements; ++ndx)
+ outputFloats[ndx] = inputFloats[ndx] + inputFloats[ndx];
+
+ for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+ {
+ map<string, string> specializations;
+ ComputeShaderSpec spec;
+
+ specializations["ACCESS"] = cases[caseNdx].param;
+ spec.assembly = shaderTemplate.specialize(specializations);
+ spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+ spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+ group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
+ }
+
+ return group.release();
+}
+
+// Checks that we can get undefined values for various types, without exercising a computation with it.
+tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
+ vector<CaseParameter> cases;
+ de::Random rnd (deStringHash(group->getName()));
+ const int numElements = 100;
+ vector<float> positiveFloats (numElements, 0);
+ vector<float> negativeFloats (numElements, 0);
+ const StringTemplate shaderTemplate (
+ string(s_ShaderPreamble) +
+
+ "OpSource GLSL 430\n"
+ "OpName %main \"main\"\n"
+ "OpName %id \"gl_GlobalInvocationID\"\n"
+
+ "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+ + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+ "${TYPE}\n"
+
+ "%id = OpVariable %uvec3ptr Input\n"
+ "%zero = OpConstant %i32 0\n"
+
+ "%main = OpFunction %void None %voidf\n"
+ "%label = OpLabel\n"
+
+ "%undef = OpUndef %type\n"
"%idval = OpLoad %uvec3 %id\n"
"%x = OpCompositeExtract %u32 %idval 0\n"
specializations["TYPE"] = cases[caseNdx].param;
spec.assembly = shaderTemplate.specialize(specializations);
- spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
- spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
+ spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
+ spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
spec.numWorkGroups = IVec3(numElements, 1, 1);
group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
return group.release();
}
-
typedef std::pair<std::string, VkShaderStageFlagBits> EntryToStage;
typedef map<string, vector<EntryToStage> > ModuleMap;
+typedef map<VkShaderStageFlagBits, vector<deInt32> > StageToSpecConstantMap;
// Context for a specific test instantiation. For example, an instantiation
// may test colors yellow/magenta/cyan/mauve in a tesselation shader
RGBA outputColors[4];
// Concrete SPIR-V code to test via boilerplate specialization.
map<string, string> testCodeFragments;
+ StageToSpecConstantMap specConstants;
- InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_)
- : testCodeFragments (testCodeFragments_)
+ bool hasTessellation;
+ InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_, const StageToSpecConstantMap& specConstants_)
+ : testCodeFragments (testCodeFragments_)
+ , specConstants (specConstants_)
+ , hasTessellation (false)
{
inputColors[0] = inputs[0];
inputColors[1] = inputs[1];
InstanceContext (const InstanceContext& other)
: moduleMap (other.moduleMap)
, testCodeFragments (other.testCodeFragments)
+ , specConstants (other.specConstants)
+ , hasTessellation (other.hasTessellation)
{
inputColors[0] = other.inputColors[0];
inputColors[1] = other.inputColors[1];
struct ShaderElement
{
// The module that contains this shader entrypoint.
- const char* moduleName;
+ string moduleName;
// The name of the entrypoint.
- const char* entryName;
+ string entryName;
// Which shader stage this entry point represents.
VkShaderStageFlagBits stage;
- ShaderElement (const char* moduleName_, const char* entryPoint_, VkShaderStageFlagBits shaderStage_)
+ ShaderElement (const string& moduleName_, const string& entryPoint_, VkShaderStageFlagBits shaderStage_)
: moduleName(moduleName_)
, entryName(entryPoint_)
, stage(shaderStage_)
{
colors[0] = RGBA::white();
colors[1] = RGBA::red();
- colors[2] = RGBA::blue();
- colors[3] = RGBA::green();
+ colors[2] = RGBA::green();
+ colors[3] = RGBA::blue();
+}
+
+void getHalfColorsFullAlpha (RGBA (&colors)[4])
+{
+ colors[0] = RGBA(127, 127, 127, 255);
+ colors[1] = RGBA(127, 0, 0, 255);
+ colors[2] = RGBA(0, 127, 0, 255);
+ colors[3] = RGBA(0, 0, 127, 255);
+}
+
+void getInvertedDefaultColors (RGBA (&colors)[4])
+{
+ colors[0] = RGBA(0, 0, 0, 255);
+ colors[1] = RGBA(0, 255, 255, 255);
+ colors[2] = RGBA(255, 0, 255, 255);
+ colors[3] = RGBA(255, 255, 0, 255);
}
// Turns a statically sized array of ShaderElements into an instance-context
// by setting up the mapping of modules to their contained shaders and stages.
// The inputs and expected outputs are given by inputColors and outputColors
template<size_t N>
-InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
+InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const StageToSpecConstantMap& specConstants)
{
- InstanceContext ctx (inputColors, outputColors, testCodeFragments);
+ InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants);
for (size_t i = 0; i < N; ++i)
{
ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
+ if (elements[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
+ elements[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+ {
+ ctx.hasTessellation = true;
+ }
}
return ctx;
}
+template<size_t N>
+inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
+{
+ return createInstanceContext(elements, inputColors, outputColors, testCodeFragments, StageToSpecConstantMap());
+}
+
// The same as createInstanceContext above, but with default colors.
template<size_t N>
InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const map<string, string>& testCodeFragments)
for (ModuleMap::const_iterator moduleNdx = instance.moduleMap.begin(); moduleNdx != instance.moduleMap.end(); ++moduleNdx)
{
const ModuleHandleSp mod(new Unique<VkShaderModule>(createShaderModule(vk, vkDevice, context.getBinaryCollection().get(moduleNdx->first), 0)));
-
modules.push_back(ModuleHandleSp(mod));
-
for (vector<EntryToStage>::const_iterator shaderNdx = moduleNdx->second.begin(); shaderNdx != moduleNdx->second.end(); ++shaderNdx)
{
const EntryToStage& stage = *shaderNdx;
stage.first.c_str(), // const char* pName;
(const VkSpecializationInfo*)DE_NULL,
};
-
createInfos.push_back(shaderParam);
}
}
}
-#define SPIRV_ASSEMBLY_TYPES \
- "%void = OpTypeVoid\n" \
- "%bool = OpTypeBool\n" \
- \
- "%i32 = OpTypeInt 32 1\n" \
- "%u32 = OpTypeInt 32 0\n" \
- \
- "%f32 = OpTypeFloat 32\n" \
- "%v3f32 = OpTypeVector %f32 3\n" \
- "%v4f32 = OpTypeVector %f32 4\n" \
- \
- "%v4f32_function = OpTypeFunction %v4f32 %v4f32\n" \
- "%fun = OpTypeFunction %void\n" \
- \
- "%ip_f32 = OpTypePointer Input %f32\n" \
- "%ip_i32 = OpTypePointer Input %i32\n" \
- "%ip_v3f32 = OpTypePointer Input %v3f32\n" \
- "%ip_v4f32 = OpTypePointer Input %v4f32\n" \
- \
- "%op_f32 = OpTypePointer Output %f32\n" \
- "%op_v4f32 = OpTypePointer Output %v4f32\n"
-
-#define SPIRV_ASSEMBLY_CONSTANTS \
- "%c_f32_1 = OpConstant %f32 1\n" \
- "%c_i32_0 = OpConstant %i32 0\n" \
- "%c_i32_1 = OpConstant %i32 1\n" \
- "%c_i32_2 = OpConstant %i32 2\n" \
- "%c_u32_0 = OpConstant %u32 0\n" \
- "%c_u32_1 = OpConstant %u32 1\n" \
- "%c_u32_2 = OpConstant %u32 2\n" \
- "%c_u32_3 = OpConstant %u32 3\n" \
- "%c_u32_32 = OpConstant %u32 32\n" \
- "%c_u32_4 = OpConstant %u32 4\n"
-
-#define SPIRV_ASSEMBLY_ARRAYS \
- "%a1f32 = OpTypeArray %f32 %c_u32_1\n" \
- "%a2f32 = OpTypeArray %f32 %c_u32_2\n" \
- "%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n" \
- "%a4f32 = OpTypeArray %f32 %c_u32_4\n" \
- "%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n" \
- "%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n" \
- "%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n" \
- "%op_a2f32 = OpTypePointer Output %a2f32\n" \
- "%op_a3v4f32 = OpTypePointer Output %a3v4f32\n" \
+#define SPIRV_ASSEMBLY_TYPES \
+ "%void = OpTypeVoid\n" \
+ "%bool = OpTypeBool\n" \
+ \
+ "%i32 = OpTypeInt 32 1\n" \
+ "%u32 = OpTypeInt 32 0\n" \
+ \
+ "%f32 = OpTypeFloat 32\n" \
+ "%v3f32 = OpTypeVector %f32 3\n" \
+ "%v4f32 = OpTypeVector %f32 4\n" \
+ \
+ "%v4f32_function = OpTypeFunction %v4f32 %v4f32\n" \
+ "%fun = OpTypeFunction %void\n" \
+ \
+ "%ip_f32 = OpTypePointer Input %f32\n" \
+ "%ip_i32 = OpTypePointer Input %i32\n" \
+ "%ip_v3f32 = OpTypePointer Input %v3f32\n" \
+ "%ip_v4f32 = OpTypePointer Input %v4f32\n" \
+ \
+ "%op_f32 = OpTypePointer Output %f32\n" \
+ "%op_v4f32 = OpTypePointer Output %v4f32\n" \
+ \
+ "%fp_f32 = OpTypePointer Function %f32\n" \
+ "%fp_i32 = OpTypePointer Function %i32\n" \
+ "%fp_v4f32 = OpTypePointer Function %v4f32\n"
+
+#define SPIRV_ASSEMBLY_CONSTANTS \
+ "%c_f32_1 = OpConstant %f32 1.0\n" \
+ "%c_f32_0 = OpConstant %f32 0.0\n" \
+ "%c_f32_0_5 = OpConstant %f32 0.5\n" \
+ "%c_f32_n1 = OpConstant %f32 -1.\n" \
+ "%c_i32_0 = OpConstant %i32 0\n" \
+ "%c_i32_1 = OpConstant %i32 1\n" \
+ "%c_i32_2 = OpConstant %i32 2\n" \
+ "%c_i32_3 = OpConstant %i32 3\n" \
+ "%c_i32_4 = OpConstant %i32 4\n" \
+ "%c_u32_0 = OpConstant %u32 0\n" \
+ "%c_u32_1 = OpConstant %u32 1\n" \
+ "%c_u32_2 = OpConstant %u32 2\n" \
+ "%c_u32_3 = OpConstant %u32 3\n" \
+ "%c_u32_32 = OpConstant %u32 32\n" \
+ "%c_u32_4 = OpConstant %u32 4\n" \
+ "%c_u32_31_bits = OpConstant %u32 0x7FFFFFFF\n" \
+ "%c_v4f32_1_1_1_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n" \
+ "%c_v4f32_1_0_0_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_1\n" \
+ "%c_v4f32_0_5_0_5_0_5_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5\n"
+
+#define SPIRV_ASSEMBLY_ARRAYS \
+ "%a1f32 = OpTypeArray %f32 %c_u32_1\n" \
+ "%a2f32 = OpTypeArray %f32 %c_u32_2\n" \
+ "%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n" \
+ "%a4f32 = OpTypeArray %f32 %c_u32_4\n" \
+ "%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n" \
+ "%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n" \
+ "%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n" \
+ "%op_a2f32 = OpTypePointer Output %a2f32\n" \
+ "%op_a3v4f32 = OpTypePointer Output %a3v4f32\n" \
"%op_a4f32 = OpTypePointer Output %a4f32\n"
// Creates vertex-shader assembly by specializing a boilerplate StringTemplate
static const char vertexShaderBoilerplate[] =
"OpCapability Shader\n"
"OpMemoryModel Logical GLSL450\n"
- "OpEntryPoint Vertex %4 \"main\" %BP_Position %BP_vtxColor %BP_color "
+ "OpEntryPoint Vertex %main \"main\" %BP_Position %BP_vtxColor %BP_color "
"%BP_vtxPosition %BP_vertex_id %BP_instance_id\n"
"${debug:opt}\n"
"OpName %main \"main\"\n"
"OpName %BP_Position \"position\"\n"
"OpName %BP_vtxColor \"vtxColor\"\n"
"OpName %BP_color \"color\"\n"
- "OpName %vertex_id \"gl_VertexID\"\n"
- "OpName %instance_id \"gl_InstanceID\"\n"
+ "OpName %BP_vertex_id \"gl_VertexID\"\n"
+ "OpName %BP_instance_id \"gl_InstanceID\"\n"
"OpName %test_code \"testfun(vf4;\"\n"
"OpDecorate %BP_vtxPosition Location 2\n"
"OpDecorate %BP_Position Location 0\n"
"OpDecorate %BP_color Location 1\n"
"OpDecorate %BP_vertex_id BuiltIn VertexId\n"
"OpDecorate %BP_instance_id BuiltIn InstanceId\n"
+ "${decoration:opt}\n"
SPIRV_ASSEMBLY_TYPES
SPIRV_ASSEMBLY_CONSTANTS
SPIRV_ASSEMBLY_ARRAYS
"%BP_color = OpVariable %ip_v4f32 Input\n"
"%BP_vertex_id = OpVariable %ip_i32 Input\n"
"%BP_instance_id = OpVariable %ip_i32 Input\n"
+ "${pre_main:opt}\n"
"%main = OpFunction %void None %fun\n"
"%BP_label = OpLabel\n"
"%BP_tmp_position = OpLoad %v4f32 %BP_Position\n"
"OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
"OpDecorate %BP_gl_TessLevelInner Patch\n"
"OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
+ "${decoration:opt}\n"
SPIRV_ASSEMBLY_TYPES
SPIRV_ASSEMBLY_CONSTANTS
SPIRV_ASSEMBLY_ARRAYS
"%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
"%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
"%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+ "${pre_main:opt}\n"
"%BP_main = OpFunction %void None %fun\n"
"%BP_label = OpLabel\n"
"OpDecorate %BP_in_position Location 2\n"
"OpDecorate %BP_out_color Location 1\n"
"OpDecorate %BP_in_color Location 1\n"
+ "${decoration:opt}\n"
SPIRV_ASSEMBLY_TYPES
SPIRV_ASSEMBLY_CONSTANTS
SPIRV_ASSEMBLY_ARRAYS
"%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
"%BP_out_color = OpVariable %op_v4f32 Output\n"
"%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
+ "${pre_main:opt}\n"
+
"%BP_main = OpFunction %void None %fun\n"
"%BP_label = OpLabel\n"
"%BP_tc_0_ptr = OpAccessChain %ip_f32 %BP_gl_tessCoord %c_u32_0\n"
"OpDecorate %BP_out_color Location 1\n"
"OpDecorate %BP_out_color Stream 0\n"
"OpDecorate %BP_in_color Location 1\n"
+ "${decoration:opt}\n"
SPIRV_ASSEMBLY_TYPES
SPIRV_ASSEMBLY_CONSTANTS
SPIRV_ASSEMBLY_ARRAYS
"%BP_out_color = OpVariable %op_v4f32 Output\n"
"%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
"%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
+ "${pre_main:opt}\n"
"%BP_main = OpFunction %void None %fun\n"
"%BP_label = OpLabel\n"
"%BP_transformed_in_color_1 = OpFunctionCall %v4f32 %test_code %BP_in_color_1\n"
"%BP_transformed_in_color_2 = OpFunctionCall %v4f32 %test_code %BP_in_color_2\n"
+
"OpStore %BP_out_gl_position %BP_in_position_0\n"
"OpStore %BP_out_color %BP_transformed_in_color_0\n"
"OpEmitVertex\n"
"OpName %test_code \"testfun(vf4;\"\n"
"OpDecorate %BP_fragColor Location 0\n"
"OpDecorate %BP_vtxColor Location 1\n"
+ "${decoration:opt}\n"
SPIRV_ASSEMBLY_TYPES
SPIRV_ASSEMBLY_CONSTANTS
SPIRV_ASSEMBLY_ARRAYS
"%BP_fragColor = OpVariable %op_v4f32 Output\n"
"%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
+ "${pre_main:opt}\n"
"%BP_main = OpFunction %void None %fun\n"
"%BP_label_main = OpLabel\n"
"%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
// Vertex shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context)
+{
map<string, string> passthru = passthruFragments();
dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
// Tessellation control shader gets custom code from context, the rest are
// pass-through.
-void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context)
+{
map<string, string> passthru = passthruFragments();
dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
// Tessellation evaluation shader gets custom code from context, the rest are
// pass-through.
-void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context)
+{
map<string, string> passthru = passthruFragments();
dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
// Geometry shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context)
+{
map<string, string> passthru = passthruFragments();
dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
// Fragment shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context)
+{
map<string, string> passthru = passthruFragments();
dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(context.testCodeFragments);
}
+void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
+{
+ // \todo [2015-12-07 awoloszyn] Make tessellation / geometry conditional
+ // \todo [2015-12-07 awoloszyn] Remove OpName and OpMemeberName at some point
+ dst.spirvAsmSources.add("module") <<
+ "OpCapability Shader\n"
+ "OpCapability Geometry\n"
+ "OpCapability Tessellation\n"
+ "OpMemoryModel Logical GLSL450\n"
+
+ "OpEntryPoint Vertex %vert_main \"main\" %vert_Position %vert_vtxColor %vert_color %vert_vtxPosition %vert_vertex_id %vert_instance_id\n"
+ "OpEntryPoint Geometry %geom_main \"main\" %out_gl_position %gl_in %out_color %in_color\n"
+ "OpEntryPoint TessellationControl %tessc_main \"main\" %tessc_out_color %tessc_gl_InvocationID %tessc_in_color %tessc_out_position %tessc_in_position %tessc_gl_TessLevelOuter %tessc_gl_TessLevelInner\n"
+ "OpEntryPoint TessellationEvaluation %tesse_main \"main\" %tesse_stream %tesse_gl_tessCoord %tesse_in_position %tesse_out_color %tesse_in_color \n"
+ "OpEntryPoint Fragment %frag_main \"main\" %frag_vtxColor %frag_fragColor\n"
+
+ "OpExecutionMode %geom_main Triangles\n"
+ "OpExecutionMode %geom_main Invocations 0\n"
+ "OpExecutionMode %geom_main OutputTriangleStrip\n"
+ "OpExecutionMode %geom_main OutputVertices 3\n"
+
+ "OpExecutionMode %tessc_main OutputVertices 3\n"
+
+ "OpExecutionMode %tesse_main Triangles\n"
+
+ "OpExecutionMode %frag_main OriginUpperLeft\n"
+
+ "; Vertex decorations\n"
+ "OpName %vert_main \"main\"\n"
+ "OpName %vert_vtxPosition \"vtxPosition\"\n"
+ "OpName %vert_Position \"position\"\n"
+ "OpName %vert_vtxColor \"vtxColor\"\n"
+ "OpName %vert_color \"color\"\n"
+ "OpName %vert_vertex_id \"gl_VertexID\"\n"
+ "OpName %vert_instance_id \"gl_InstanceID\"\n"
+ "OpDecorate %vert_vtxPosition Location 2\n"
+ "OpDecorate %vert_Position Location 0\n"
+ "OpDecorate %vert_vtxColor Location 1\n"
+ "OpDecorate %vert_color Location 1\n"
+ "OpDecorate %vert_vertex_id BuiltIn VertexId\n"
+ "OpDecorate %vert_instance_id BuiltIn InstanceId\n"
+
+ "; Geometry decorations\n"
+ "OpName %geom_main \"main\"\n"
+ "OpName %per_vertex_in \"gl_PerVertex\"\n"
+ "OpMemberName %per_vertex_in 0 \"gl_Position\"\n"
+ "OpMemberName %per_vertex_in 1 \"gl_PointSize\"\n"
+ "OpMemberName %per_vertex_in 2 \"gl_ClipDistance\"\n"
+ "OpMemberName %per_vertex_in 3 \"gl_CullDistance\"\n"
+ "OpName %gl_in \"gl_in\"\n"
+ "OpName %out_color \"out_color\"\n"
+ "OpName %in_color \"in_color\"\n"
+ "OpDecorate %out_gl_position BuiltIn Position\n"
+ "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
+ "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
+ "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
+ "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
+ "OpDecorate %per_vertex_in Block\n"
+ "OpDecorate %out_color Location 1\n"
+ "OpDecorate %out_color Stream 0\n"
+ "OpDecorate %in_color Location 1\n"
+
+ "; Tessellation Control decorations\n"
+ "OpName %tessc_main \"main\"\n"
+ "OpName %tessc_out_color \"out_color\"\n"
+ "OpName %tessc_gl_InvocationID \"gl_InvocationID\"\n"
+ "OpName %tessc_in_color \"in_color\"\n"
+ "OpName %tessc_out_position \"out_position\"\n"
+ "OpName %tessc_in_position \"in_position\"\n"
+ "OpName %tessc_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
+ "OpName %tessc_gl_TessLevelInner \"gl_TessLevelInner\"\n"
+ "OpDecorate %tessc_out_color Location 1\n"
+ "OpDecorate %tessc_gl_InvocationID BuiltIn InvocationId\n"
+ "OpDecorate %tessc_in_color Location 1\n"
+ "OpDecorate %tessc_out_position Location 2\n"
+ "OpDecorate %tessc_in_position Location 2\n"
+ "OpDecorate %tessc_gl_TessLevelOuter Patch\n"
+ "OpDecorate %tessc_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
+ "OpDecorate %tessc_gl_TessLevelInner Patch\n"
+ "OpDecorate %tessc_gl_TessLevelInner BuiltIn TessLevelInner\n"
+
+ "; Tessellation Evaluation decorations\n"
+ "OpName %tesse_main \"main\"\n"
+ "OpName %tesse_per_vertex_out \"gl_PerVertex\"\n"
+ "OpMemberName %tesse_per_vertex_out 0 \"gl_Position\"\n"
+ "OpMemberName %tesse_per_vertex_out 1 \"gl_PointSize\"\n"
+ "OpMemberName %tesse_per_vertex_out 2 \"gl_ClipDistance\"\n"
+ "OpMemberName %tesse_per_vertex_out 3 \"gl_CullDistance\"\n"
+ "OpName %tesse_stream \"\"\n"
+ "OpName %tesse_gl_tessCoord \"gl_TessCoord\"\n"
+ "OpName %tesse_in_position \"in_position\"\n"
+ "OpName %tesse_out_color \"out_color\"\n"
+ "OpName %tesse_in_color \"in_color\"\n"
+ "OpMemberDecorate %tesse_per_vertex_out 0 BuiltIn Position\n"
+ "OpMemberDecorate %tesse_per_vertex_out 1 BuiltIn PointSize\n"
+ "OpMemberDecorate %tesse_per_vertex_out 2 BuiltIn ClipDistance\n"
+ "OpMemberDecorate %tesse_per_vertex_out 3 BuiltIn CullDistance\n"
+ "OpDecorate %tesse_per_vertex_out Block\n"
+ "OpDecorate %tesse_gl_tessCoord BuiltIn TessCoord\n"
+ "OpDecorate %tesse_in_position Location 2\n"
+ "OpDecorate %tesse_out_color Location 1\n"
+ "OpDecorate %tesse_in_color Location 1\n"
+
+ "; Fragment decorations\n"
+ "OpName %frag_main \"main\"\n"
+ "OpName %frag_fragColor \"fragColor\"\n"
+ "OpName %frag_vtxColor \"vtxColor\"\n"
+ "OpDecorate %frag_fragColor Location 0\n"
+ "OpDecorate %frag_vtxColor Location 1\n"
+
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+
+ "; Vertex Variables\n"
+ "%vert_vtxPosition = OpVariable %op_v4f32 Output\n"
+ "%vert_Position = OpVariable %ip_v4f32 Input\n"
+ "%vert_vtxColor = OpVariable %op_v4f32 Output\n"
+ "%vert_color = OpVariable %ip_v4f32 Input\n"
+ "%vert_vertex_id = OpVariable %ip_i32 Input\n"
+ "%vert_instance_id = OpVariable %ip_i32 Input\n"
+
+ "; Geometry Variables\n"
+ "%geom_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+ "%geom_a3_per_vertex_in = OpTypeArray %geom_per_vertex_in %c_u32_3\n"
+ "%geom_ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
+ "%geom_gl_in = OpVariable %geom_ip_a3_per_vertex_in Input\n"
+ "%geom_out_color = OpVariable %op_v4f32 Output\n"
+ "%geom_in_color = OpVariable %ip_a3v4f32 Input\n"
+ "%geom_out_gl_position = OpVariable %op_v4f32 Output\n"
+
+ "; Tessellation Control Variables\n"
+ "%tessc_out_color = OpVariable %op_a3v4f32 Output\n"
+ "%tessc_gl_InvocationID = OpVariable %ip_i32 Input\n"
+ "%tessc_in_color = OpVariable %ip_a32v4f32 Input\n"
+ "%tessc_out_position = OpVariable %op_a3v4f32 Output\n"
+ "%tessc_in_position = OpVariable %ip_a32v4f32 Input\n"
+ "%tessc_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
+ "%tessc_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+
+ "; Tessellation Evaluation Decorations\n"
+ "%tesse_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+ "%tesse_op_per_vertex_out = OpTypePointer Output %tesse_per_vertex_out\n"
+ "%tesse_stream = OpVariable %tesse_op_per_vertex_out Output\n"
+ "%tesse_gl_tessCoord = OpVariable %ip_v3f32 Input\n"
+ "%tesse_in_position = OpVariable %ip_a32v4f32 Input\n"
+ "%tesse_out_color = OpVariable %op_v4f32 Output\n"
+ "%tesse_in_color = OpVariable %ip_a32v4f32 Input\n"
+
+ "; Fragment Variables\n"
+ "%frag_fragColor = OpVariable %op_v4f32 Output\n"
+ "%frag_vtxColor = OpVariable %ip_v4f32 Input\n"
+
+ "; Vertex Entry\n"
+ "%vert_main = OpFunction %void None %fun\n"
+ "%vert_label = OpLabel\n"
+ "%vert_tmp_position = OpLoad %v4f32 %vert_Position\n"
+ "OpStore %vert_vtxPosition %vert_tmp_position\n"
+ "%vert_tmp_color = OpLoad %v4f32 %vert_color\n"
+ "OpStore %vert_vtxColor %vert_tmp_color\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "; Geometry Entry\n"
+ "%geom_main = OpFunction %void None %fun\n"
+ "%geom_label = OpLabel\n"
+ "%geom_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_0 %c_i32_0\n"
+ "%geom_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_1 %c_i32_0\n"
+ "%geom_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_2 %c_i32_0\n"
+ "%geom_in_position_0 = OpLoad %v4f32 %geom_gl_in_0_gl_position\n"
+ "%geom_in_position_1 = OpLoad %v4f32 %geom_gl_in_1_gl_position\n"
+ "%geom_in_position_2 = OpLoad %v4f32 %geom_gl_in_2_gl_position \n"
+ "%geom_in_color_0_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_0\n"
+ "%geom_in_color_1_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_1\n"
+ "%geom_in_color_2_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_2\n"
+ "%geom_in_color_0 = OpLoad %v4f32 %geom_in_color_0_ptr\n"
+ "%geom_in_color_1 = OpLoad %v4f32 %geom_in_color_1_ptr\n"
+ "%geom_in_color_2 = OpLoad %v4f32 %geom_in_color_2_ptr\n"
+ "OpStore %geom_out_gl_position %geom_in_position_0\n"
+ "OpStore %geom_out_color %geom_in_color_0\n"
+ "OpEmitVertex\n"
+ "OpStore %geom_out_gl_position %geom_in_position_1\n"
+ "OpStore %geom_out_color %geom_in_color_1\n"
+ "OpEmitVertex\n"
+ "OpStore %geom_out_gl_position %geom_in_position_2\n"
+ "OpStore %geom_out_color %geom_in_color_2\n"
+ "OpEmitVertex\n"
+ "OpEndPrimitive\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "; Tessellation Control Entry\n"
+ "%tessc_main = OpFunction %void None %fun\n"
+ "%tessc_label = OpLabel\n"
+ "%tessc_invocation_id = OpLoad %i32 %tessc_gl_InvocationID\n"
+ "%tessc_in_color_ptr = OpAccessChain %ip_v4f32 %tessc_in_color %tessc_invocation_id\n"
+ "%tessc_in_position_ptr = OpAccessChain %ip_v4f32 %tessc_in_position %tessc_invocation_id\n"
+ "%tessc_in_color_val = OpLoad %v4f32 %tessc_in_color_ptr\n"
+ "%tessc_in_position_val = OpLoad %v4f32 %tessc_in_position_ptr\n"
+ "%tessc_out_color_ptr = OpAccessChain %op_v4f32 %tessc_out_color %tessc_invocation_id\n"
+ "%tessc_out_position_ptr = OpAccessChain %op_v4f32 %tessc_out_position %tessc_invocation_id\n"
+ "OpStore %tessc_out_color_ptr %tessc_in_color_val\n"
+ "OpStore %tessc_out_position_ptr %tessc_in_position_val\n"
+ "%tessc_is_first_invocation = OpIEqual %bool %tessc_invocation_id %c_i32_0\n"
+ "OpSelectionMerge %tessc_merge_label None\n"
+ "OpBranchConditional %tessc_is_first_invocation %tessc_first_invocation %tessc_merge_label\n"
+ "%tessc_first_invocation = OpLabel\n"
+ "%tessc_tess_outer_0 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_0\n"
+ "%tessc_tess_outer_1 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_1\n"
+ "%tessc_tess_outer_2 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_2\n"
+ "%tessc_tess_inner = OpAccessChain %op_f32 %tessc_gl_TessLevelInner %c_i32_0\n"
+ "OpStore %tessc_tess_outer_0 %c_f32_1\n"
+ "OpStore %tessc_tess_outer_1 %c_f32_1\n"
+ "OpStore %tessc_tess_outer_2 %c_f32_1\n"
+ "OpStore %tessc_tess_inner %c_f32_1\n"
+ "OpBranch %tessc_merge_label\n"
+ "%tessc_merge_label = OpLabel\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "; Tessellation Evaluation Entry\n"
+ "%tesse_main = OpFunction %void None %fun\n"
+ "%tesse_label = OpLabel\n"
+ "%tesse_tc_0_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_0\n"
+ "%tesse_tc_1_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_1\n"
+ "%tesse_tc_2_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_2\n"
+ "%tesse_tc_0 = OpLoad %f32 %tesse_tc_0_ptr\n"
+ "%tesse_tc_1 = OpLoad %f32 %tesse_tc_1_ptr\n"
+ "%tesse_tc_2 = OpLoad %f32 %tesse_tc_2_ptr\n"
+ "%tesse_in_pos_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_0\n"
+ "%tesse_in_pos_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_1\n"
+ "%tesse_in_pos_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_2\n"
+ "%tesse_in_pos_0 = OpLoad %v4f32 %tesse_in_pos_0_ptr\n"
+ "%tesse_in_pos_1 = OpLoad %v4f32 %tesse_in_pos_1_ptr\n"
+ "%tesse_in_pos_2 = OpLoad %v4f32 %tesse_in_pos_2_ptr\n"
+ "%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %BP_tc_0 %tesse_in_pos_0\n"
+ "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %BP_tc_1 %tesse_in_pos_1\n"
+ "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %BP_tc_2 %tesse_in_pos_2\n"
+ "%tesse_out_pos_ptr = OpAccessChain %op_v4f32 %tesse_stream %c_i32_0\n"
+ "%tesse_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse_in_pos_0_weighted %tesse_in_pos_1_weighted\n"
+ "%tesse_computed_out = OpFAdd %v4f32 %tesse_in_pos_0_plus_pos_1 %tesse_in_pos_2_weighted\n"
+ "OpStore %tesse_out_pos_ptr %tesse_computed_out\n"
+ "%tesse_in_clr_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_0\n"
+ "%tesse_in_clr_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_1\n"
+ "%tesse_in_clr_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_2\n"
+ "%tesse_in_clr_0 = OpLoad %v4f32 %tesse_in_clr_0_ptr\n"
+ "%tesse_in_clr_1 = OpLoad %v4f32 %tesse_in_clr_1_ptr\n"
+ "%tesse_in_clr_2 = OpLoad %v4f32 %tesse_in_clr_2_ptr\n"
+ "%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_0 %tesse_in_clr_0\n"
+ "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_1 %tesse_in_clr_1\n"
+ "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_2 %tesse_in_clr_2\n"
+ "%tesse_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse_in_clr_0_weighted %tesse_in_clr_1_weighted\n"
+ "%tesse_computed_clr = OpFAdd %v4f32 %tesse_in_clr_0_plus_col_1 %tesse_in_clr_2_weighted\n"
+ "OpStore %tesse_out_color %tesse_computed_clr\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "; Fragment Entry\n"
+ "%frag_main = OpFunction %void None %fun\n"
+ "%frag_label_main = OpLabel\n"
+ "%frag_tmp1 = OpLoad %v4f32 %frag_vtxColor\n"
+ "OpStore %frag_fragColor %frag_tmp1\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+}
+
+// This has two shaders of each stage. The first
+// is a passthrough, the second inverts the color.
+void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
+{
+ dst.spirvAsmSources.add("vert") <<
+ // This module contains 2 vertex shaders. One that is a passthrough
+ // and a second that inverts the color of the output (1.0 - color).
+ "OpCapability Shader\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint Vertex %main \"vert1\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
+ "OpEntryPoint Vertex %main2 \"vert2\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
+
+ "OpName %main \"frag1\"\n"
+ "OpName %main2 \"frag2\"\n"
+ "OpName %vtxPosition \"vtxPosition\"\n"
+ "OpName %Position \"position\"\n"
+ "OpName %vtxColor \"vtxColor\"\n"
+ "OpName %color \"color\"\n"
+ "OpName %vertex_id \"gl_VertexID\"\n"
+ "OpName %instance_id \"gl_InstanceID\"\n"
+ "OpName %test_code \"testfun(vf4;\"\n"
+
+ "OpDecorate %vtxPosition Location 2\n"
+ "OpDecorate %Position Location 0\n"
+ "OpDecorate %vtxColor Location 1\n"
+ "OpDecorate %color Location 1\n"
+ "OpDecorate %vertex_id BuiltIn VertexId\n"
+ "OpDecorate %instance_id BuiltIn InstanceId\n"
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+ "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%vtxPosition = OpVariable %op_v4f32 Output\n"
+ "%Position = OpVariable %ip_v4f32 Input\n"
+ "%vtxColor = OpVariable %op_v4f32 Output\n"
+ "%color = OpVariable %ip_v4f32 Input\n"
+ "%vertex_id = OpVariable %ip_i32 Input\n"
+ "%instance_id = OpVariable %ip_i32 Input\n"
+
+ "%main = OpFunction %void None %fun\n"
+ "%label = OpLabel\n"
+ "%tmp_position = OpLoad %v4f32 %Position\n"
+ "OpStore %vtxPosition %tmp_position\n"
+ "%tmp_color = OpLoad %v4f32 %color\n"
+ "OpStore %vtxColor %tmp_color\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "%main2 = OpFunction %void None %fun\n"
+ "%label2 = OpLabel\n"
+ "%tmp_position2 = OpLoad %v4f32 %Position\n"
+ "OpStore %vtxPosition %tmp_position2\n"
+ "%tmp_color2 = OpLoad %v4f32 %color\n"
+ "%tmp_color3 = OpFSub %v4f32 %cval %tmp_color2\n"
+ "OpStore %vtxColor %tmp_color3\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+
+ dst.spirvAsmSources.add("frag") <<
+ // This is a single module that contains 2 fragment shaders.
+ // One that passes color through and the other that inverts the output
+ // color (1.0 - color).
+ "OpCapability Shader\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint Fragment %main \"frag1\" %vtxColor %fragColor\n"
+ "OpEntryPoint Fragment %main2 \"frag2\" %vtxColor %fragColor\n"
+ "OpExecutionMode %main OriginUpperLeft\n"
+ "OpExecutionMode %main2 OriginUpperLeft\n"
+
+ "OpName %main \"frag1\"\n"
+ "OpName %main2 \"frag2\"\n"
+ "OpName %fragColor \"fragColor\"\n"
+ "OpName %vtxColor \"vtxColor\"\n"
+ "OpDecorate %fragColor Location 0\n"
+ "OpDecorate %vtxColor Location 1\n"
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+ "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%fragColor = OpVariable %op_v4f32 Output\n"
+ "%vtxColor = OpVariable %ip_v4f32 Input\n"
+
+ "%main = OpFunction %void None %fun\n"
+ "%label_main = OpLabel\n"
+ "%tmp1 = OpLoad %v4f32 %vtxColor\n"
+ "OpStore %fragColor %tmp1\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "%main2 = OpFunction %void None %fun\n"
+ "%label_main2 = OpLabel\n"
+ "%tmp2 = OpLoad %v4f32 %vtxColor\n"
+ "%tmp3 = OpFSub %v4f32 %cval %tmp2\n"
+ "OpStore %fragColor %tmp3\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+
+ dst.spirvAsmSources.add("geom") <<
+ "OpCapability Geometry\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint Geometry %geom1_main \"geom1\" %out_gl_position %gl_in %out_color %in_color\n"
+ "OpEntryPoint Geometry %geom2_main \"geom2\" %out_gl_position %gl_in %out_color %in_color\n"
+ "OpExecutionMode %geom1_main Triangles\n"
+ "OpExecutionMode %geom2_main Triangles\n"
+ "OpExecutionMode %geom1_main Invocations 0\n"
+ "OpExecutionMode %geom2_main Invocations 0\n"
+ "OpExecutionMode %geom1_main OutputTriangleStrip\n"
+ "OpExecutionMode %geom2_main OutputTriangleStrip\n"
+ "OpExecutionMode %geom1_main OutputVertices 3\n"
+ "OpExecutionMode %geom2_main OutputVertices 3\n"
+ "OpName %geom1_main \"geom1\"\n"
+ "OpName %geom2_main \"geom2\"\n"
+ "OpName %per_vertex_in \"gl_PerVertex\"\n"
+ "OpMemberName %per_vertex_in 0 \"gl_Position\"\n"
+ "OpMemberName %per_vertex_in 1 \"gl_PointSize\"\n"
+ "OpMemberName %per_vertex_in 2 \"gl_ClipDistance\"\n"
+ "OpMemberName %per_vertex_in 3 \"gl_CullDistance\"\n"
+ "OpName %gl_in \"gl_in\"\n"
+ "OpName %out_color \"out_color\"\n"
+ "OpName %in_color \"in_color\"\n"
+ "OpDecorate %out_gl_position BuiltIn Position\n"
+ "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
+ "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
+ "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
+ "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
+ "OpDecorate %per_vertex_in Block\n"
+ "OpDecorate %out_color Location 1\n"
+ "OpDecorate %out_color Stream 0\n"
+ "OpDecorate %in_color Location 1\n"
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+ "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+ "%a3_per_vertex_in = OpTypeArray %per_vertex_in %c_u32_3\n"
+ "%ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
+ "%gl_in = OpVariable %ip_a3_per_vertex_in Input\n"
+ "%out_color = OpVariable %op_v4f32 Output\n"
+ "%in_color = OpVariable %ip_a3v4f32 Input\n"
+ "%out_gl_position = OpVariable %op_v4f32 Output\n"
+
+ "%geom1_main = OpFunction %void None %fun\n"
+ "%geom1_label = OpLabel\n"
+ "%geom1_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
+ "%geom1_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
+ "%geom1_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
+ "%geom1_in_position_0 = OpLoad %v4f32 %geom1_gl_in_0_gl_position\n"
+ "%geom1_in_position_1 = OpLoad %v4f32 %geom1_gl_in_1_gl_position\n"
+ "%geom1_in_position_2 = OpLoad %v4f32 %geom1_gl_in_2_gl_position \n"
+ "%geom1_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+ "%geom1_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+ "%geom1_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+ "%geom1_in_color_0 = OpLoad %v4f32 %geom1_in_color_0_ptr\n"
+ "%geom1_in_color_1 = OpLoad %v4f32 %geom1_in_color_1_ptr\n"
+ "%geom1_in_color_2 = OpLoad %v4f32 %geom1_in_color_2_ptr\n"
+ "OpStore %out_gl_position %geom1_in_position_0\n"
+ "OpStore %out_color %geom1_in_color_0\n"
+ "OpEmitVertex\n"
+ "OpStore %out_gl_position %geom1_in_position_1\n"
+ "OpStore %out_color %geom1_in_color_1\n"
+ "OpEmitVertex\n"
+ "OpStore %out_gl_position %geom1_in_position_2\n"
+ "OpStore %out_color %geom1_in_color_2\n"
+ "OpEmitVertex\n"
+ "OpEndPrimitive\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "%geom2_main = OpFunction %void None %fun\n"
+ "%geom2_label = OpLabel\n"
+ "%geom2_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
+ "%geom2_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
+ "%geom2_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
+ "%geom2_in_position_0 = OpLoad %v4f32 %geom2_gl_in_0_gl_position\n"
+ "%geom2_in_position_1 = OpLoad %v4f32 %geom2_gl_in_1_gl_position\n"
+ "%geom2_in_position_2 = OpLoad %v4f32 %geom2_gl_in_2_gl_position \n"
+ "%geom2_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+ "%geom2_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+ "%geom2_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+ "%geom2_in_color_0 = OpLoad %v4f32 %geom2_in_color_0_ptr\n"
+ "%geom2_in_color_1 = OpLoad %v4f32 %geom2_in_color_1_ptr\n"
+ "%geom2_in_color_2 = OpLoad %v4f32 %geom2_in_color_2_ptr\n"
+ "%geom2_transformed_in_color_0 = OpFSub %v4f32 %cval %geom2_in_color_0\n"
+ "%geom2_transformed_in_color_1 = OpFSub %v4f32 %cval %geom2_in_color_1\n"
+ "%geom2_transformed_in_color_2 = OpFSub %v4f32 %cval %geom2_in_color_2\n"
+ "OpStore %out_gl_position %geom2_in_position_0\n"
+ "OpStore %out_color %geom2_transformed_in_color_0\n"
+ "OpEmitVertex\n"
+ "OpStore %out_gl_position %geom2_in_position_1\n"
+ "OpStore %out_color %geom2_transformed_in_color_1\n"
+ "OpEmitVertex\n"
+ "OpStore %out_gl_position %geom2_in_position_2\n"
+ "OpStore %out_color %geom2_transformed_in_color_2\n"
+ "OpEmitVertex\n"
+ "OpEndPrimitive\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+
+ dst.spirvAsmSources.add("tessc") <<
+ "OpCapability Tessellation\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint TessellationControl %tessc1_main \"tessc1\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
+ "OpEntryPoint TessellationControl %tessc2_main \"tessc2\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
+ "OpExecutionMode %tessc1_main OutputVertices 3\n"
+ "OpExecutionMode %tessc2_main OutputVertices 3\n"
+ "OpName %tessc1_main \"tessc1\"\n"
+ "OpName %tessc2_main \"tessc2\"\n"
+ "OpName %out_color \"out_color\"\n"
+ "OpName %gl_InvocationID \"gl_InvocationID\"\n"
+ "OpName %in_color \"in_color\"\n"
+ "OpName %out_position \"out_position\"\n"
+ "OpName %in_position \"in_position\"\n"
+ "OpName %gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
+ "OpName %gl_TessLevelInner \"gl_TessLevelInner\"\n"
+ "OpDecorate %out_color Location 1\n"
+ "OpDecorate %gl_InvocationID BuiltIn InvocationId\n"
+ "OpDecorate %in_color Location 1\n"
+ "OpDecorate %out_position Location 2\n"
+ "OpDecorate %in_position Location 2\n"
+ "OpDecorate %gl_TessLevelOuter Patch\n"
+ "OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter\n"
+ "OpDecorate %gl_TessLevelInner Patch\n"
+ "OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner\n"
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+ "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%out_color = OpVariable %op_a3v4f32 Output\n"
+ "%gl_InvocationID = OpVariable %ip_i32 Input\n"
+ "%in_color = OpVariable %ip_a32v4f32 Input\n"
+ "%out_position = OpVariable %op_a3v4f32 Output\n"
+ "%in_position = OpVariable %ip_a32v4f32 Input\n"
+ "%gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
+ "%gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+
+ "%tessc1_main = OpFunction %void None %fun\n"
+ "%tessc1_label = OpLabel\n"
+ "%tessc1_invocation_id = OpLoad %i32 %gl_InvocationID\n"
+ "%tessc1_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc1_invocation_id\n"
+ "%tessc1_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc1_invocation_id\n"
+ "%tessc1_in_color_val = OpLoad %v4f32 %tessc1_in_color_ptr\n"
+ "%tessc1_in_position_val = OpLoad %v4f32 %tessc1_in_position_ptr\n"
+ "%tessc1_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc1_invocation_id\n"
+ "%tessc1_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc1_invocation_id\n"
+ "OpStore %tessc1_out_color_ptr %tessc1_in_color_val\n"
+ "OpStore %tessc1_out_position_ptr %tessc1_in_position_val\n"
+ "%tessc1_is_first_invocation = OpIEqual %bool %tessc1_invocation_id %c_i32_0\n"
+ "OpSelectionMerge %tessc1_merge_label None\n"
+ "OpBranchConditional %tessc1_is_first_invocation %tessc1_first_invocation %tessc1_merge_label\n"
+ "%tessc1_first_invocation = OpLabel\n"
+ "%tessc1_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
+ "%tessc1_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
+ "%tessc1_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
+ "%tessc1_tess_inner = OpAccessChain %op_f32 %tessc1_gl_TessLevelInner %c_i32_0\n"
+ "OpStore %tessc1_tess_outer_0 %c_f32_1\n"
+ "OpStore %tessc1_tess_outer_1 %c_f32_1\n"
+ "OpStore %tessc1_tess_outer_2 %c_f32_1\n"
+ "OpStore %tessc1_tess_inner %c_f32_1\n"
+ "OpBranch %tessc1_merge_label\n"
+ "%tessc1_merge_label = OpLabel\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "%tessc2_main = OpFunction %void None %fun\n"
+ "%tessc2_label = OpLabel\n"
+ "%tessc2_invocation_id = OpLoad %i32 %gl_InvocationID\n"
+ "%tessc2_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc2_invocation_id\n"
+ "%tessc2_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc2_invocation_id\n"
+ "%tessc2_in_color_val = OpLoad %v4f32 %tessc2_in_color_ptr\n"
+ "%tessc2_in_position_val = OpLoad %v4f32 %tessc2_in_position_ptr\n"
+ "%tessc2_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc2_invocation_id\n"
+ "%tessc2_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc2_invocation_id\n"
+ "%tessc2_transformed_color = OpFSub %v4f32 %cval %tessc2_in_color_val\n"
+ "OpStore %tessc2_out_color_ptr %tessc2_transformed_color\n"
+ "OpStore %tessc2_out_position_ptr %tessc2_in_position_val\n"
+ "%tessc2_is_first_invocation = OpIEqual %bool %tessc2_invocation_id %c_i32_0\n"
+ "OpSelectionMerge %tessc2_merge_label None\n"
+ "OpBranchConditional %tessc2_is_first_invocation %tessc2_first_invocation %tessc2_merge_label\n"
+ "%tessc2_first_invocation = OpLabel\n"
+ "%tessc2_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
+ "%tessc2_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
+ "%tessc2_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
+ "%tessc2_tess_inner = OpAccessChain %op_f32 %tessc2_gl_TessLevelInner %c_i32_0\n"
+ "OpStore %tessc2_tess_outer_0 %c_f32_1\n"
+ "OpStore %tessc2_tess_outer_1 %c_f32_1\n"
+ "OpStore %tessc2_tess_outer_2 %c_f32_1\n"
+ "OpStore %tessc2_tess_inner %c_f32_1\n"
+ "OpBranch %tessc2_merge_label\n"
+ "%tessc2_merge_label = OpLabel\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+
+ dst.spirvAsmSources.add("tesse") <<
+ "OpCapability Tessellation\n"
+ "OpMemoryModel Logical GLSL450\n"
+ "OpEntryPoint TessellationEvaluation %tesse1_main \"tesse1\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
+ "OpEntryPoint TessellationEvaluation %tesse2_main \"tesse2\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
+ "OpExecutionMode %tesse1_main Triangles\n"
+ "OpExecutionMode %tesse2_main Triangles\n"
+ "OpName %tesse1_main \"tesse1\"\n"
+ "OpName %tesse2_main \"tesse2\"\n"
+ "OpName %per_vertex_out \"gl_PerVertex\"\n"
+ "OpMemberName %per_vertex_out 0 \"gl_Position\"\n"
+ "OpMemberName %per_vertex_out 1 \"gl_PointSize\"\n"
+ "OpMemberName %per_vertex_out 2 \"gl_ClipDistance\"\n"
+ "OpMemberName %per_vertex_out 3 \"gl_CullDistance\"\n"
+ "OpName %stream \"\"\n"
+ "OpName %gl_tessCoord \"gl_TessCoord\"\n"
+ "OpName %in_position \"in_position\"\n"
+ "OpName %out_color \"out_color\"\n"
+ "OpName %in_color \"in_color\"\n"
+ "OpMemberDecorate %per_vertex_out 0 BuiltIn Position\n"
+ "OpMemberDecorate %per_vertex_out 1 BuiltIn PointSize\n"
+ "OpMemberDecorate %per_vertex_out 2 BuiltIn ClipDistance\n"
+ "OpMemberDecorate %per_vertex_out 3 BuiltIn CullDistance\n"
+ "OpDecorate %per_vertex_out Block\n"
+ "OpDecorate %gl_tessCoord BuiltIn TessCoord\n"
+ "OpDecorate %in_position Location 2\n"
+ "OpDecorate %out_color Location 1\n"
+ "OpDecorate %in_color Location 1\n"
+ SPIRV_ASSEMBLY_TYPES
+ SPIRV_ASSEMBLY_CONSTANTS
+ SPIRV_ASSEMBLY_ARRAYS
+ "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+ "%op_per_vertex_out = OpTypePointer Output %per_vertex_out\n"
+ "%stream = OpVariable %op_per_vertex_out Output\n"
+ "%gl_tessCoord = OpVariable %ip_v3f32 Input\n"
+ "%in_position = OpVariable %ip_a32v4f32 Input\n"
+ "%out_color = OpVariable %op_v4f32 Output\n"
+ "%in_color = OpVariable %ip_a32v4f32 Input\n"
+
+ "%tesse1_main = OpFunction %void None %fun\n"
+ "%tesse1_label = OpLabel\n"
+ "%tesse1_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
+ "%tesse1_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
+ "%tesse1_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
+ "%tesse1_tc_0 = OpLoad %f32 %tesse1_tc_0_ptr\n"
+ "%tesse1_tc_1 = OpLoad %f32 %tesse1_tc_1_ptr\n"
+ "%tesse1_tc_2 = OpLoad %f32 %tesse1_tc_2_ptr\n"
+ "%tesse1_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
+ "%tesse1_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
+ "%tesse1_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
+ "%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
+ "%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
+ "%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
+ "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %tesse1_in_pos_0\n"
+ "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %tesse1_in_pos_1\n"
+ "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %tesse1_in_pos_2\n"
+ "%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
+ "%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
+ "%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
+ "OpStore %tesse1_out_pos_ptr %tesse1_computed_out\n"
+ "%tesse1_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+ "%tesse1_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+ "%tesse1_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+ "%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
+ "%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
+ "%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
+ "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %in_clr_0\n"
+ "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %in_clr_1\n"
+ "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %in_clr_2\n"
+ "%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
+ "%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
+ "OpStore %out_color %tesse1_computed_clr\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n"
+
+ "%tesse2_main = OpFunction %void None %fun\n"
+ "%tesse2_label = OpLabel\n"
+ "%tesse2_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
+ "%tesse2_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
+ "%tesse2_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
+ "%tesse2_tc_0 = OpLoad %f32 %tesse2_tc_0_ptr\n"
+ "%tesse2_tc_1 = OpLoad %f32 %tesse2_tc_1_ptr\n"
+ "%tesse2_tc_2 = OpLoad %f32 %tesse2_tc_2_ptr\n"
+ "%tesse2_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
+ "%tesse2_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
+ "%tesse2_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
+ "%tesse2_in_pos_0 = OpLoad %v4f32 %tesse2_in_pos_0_ptr\n"
+ "%tesse2_in_pos_1 = OpLoad %v4f32 %tesse2_in_pos_1_ptr\n"
+ "%tesse2_in_pos_2 = OpLoad %v4f32 %tesse2_in_pos_2_ptr\n"
+ "%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %tesse2_in_pos_0\n"
+ "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %tesse2_in_pos_1\n"
+ "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %tesse2_in_pos_2\n"
+ "%tesse2_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
+ "%tesse2_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse2_in_pos_0_weighted %tesse2_in_pos_1_weighted\n"
+ "%tesse2_computed_out = OpFAdd %v4f32 %tesse2_in_pos_0_plus_pos_1 %tesse2_in_pos_2_weighted\n"
+ "OpStore %tesse2_out_pos_ptr %tesse2_computed_out\n"
+ "%tesse2_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+ "%tesse2_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+ "%tesse2_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+ "%tesse2_in_clr_0 = OpLoad %v4f32 %tesse2_in_clr_0_ptr\n"
+ "%tesse2_in_clr_1 = OpLoad %v4f32 %tesse2_in_clr_1_ptr\n"
+ "%tesse2_in_clr_2 = OpLoad %v4f32 %tesse2_in_clr_2_ptr\n"
+ "%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %in_clr_0\n"
+ "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %in_clr_1\n"
+ "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %in_clr_2\n"
+ "%tesse2_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse2_in_clr_0_weighted %tesse2_in_clr_1_weighted\n"
+ "%tesse2_computed_clr = OpFAdd %v4f32 %tesse2_in_clr_0_plus_col_1 %tesse2_in_clr_2_weighted\n"
+ "%tesse2_clr_transformed = OpFSub %v4f32 %cval %tesse2_computed_clr\n"
+ "OpStore %out_color %tesse2_clr_transformed\n"
+ "OpReturn\n"
+ "OpFunctionEnd\n";
+}
+
// Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
// Feeds the pipeline a set of colored triangles, which then must occur in the
// rendered image. The surface is cleared before executing the pipeline, so
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // deUint32 preserveCount;
DE_NULL, // const VkAttachmentReference* pPreserveAttachments;
+
};
const VkRenderPassCreateInfo renderPassParams =
{
};
const Unique<VkImageView> colorAttView (createImageView(vk, vkDevice, &colorAttViewParams));
+
// Pipeline layout
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
const Unique<VkPipelineLayout> pipelineLayout (createPipelineLayout(vk, vkDevice, &pipelineLayoutParams));
// Pipeline
- vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
-
+ vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
+ // We need these vectors to make sure that information about specialization constants for each stage can outlive createGraphicsPipeline().
+ vector<vector<VkSpecializationMapEntry> > specConstantEntries;
+ vector<VkSpecializationInfo> specializationInfos;
createPipelineShaderStages(vk, vkDevice, instance, context, modules, shaderStageParams);
+ // And we don't want the reallocation of these vectors to invalidate pointers pointing to their contents.
+ specConstantEntries.reserve(shaderStageParams.size());
+ specializationInfos.reserve(shaderStageParams.size());
+
+ // Patch the specialization info field in PipelineShaderStageCreateInfos.
+ for (vector<VkPipelineShaderStageCreateInfo>::iterator stageInfo = shaderStageParams.begin(); stageInfo != shaderStageParams.end(); ++stageInfo)
+ {
+ const StageToSpecConstantMap::const_iterator stageIt = instance.specConstants.find(stageInfo->stage);
+
+ if (stageIt != instance.specConstants.end())
+ {
+ const size_t numSpecConstants = stageIt->second.size();
+ vector<VkSpecializationMapEntry> entries;
+ VkSpecializationInfo specInfo;
+
+ entries.reserve(numSpecConstants);
+
+ // Only support 32-bit integers as spec constants now. And their constant IDs are numbered sequentially starting from 0.
+ for (size_t ndx = 0; ndx < numSpecConstants; ++ndx)
+ {
+ entries[ndx].constantID = (deUint32)ndx;
+ entries[ndx].offset = deUint32(ndx * sizeof(deInt32));
+ entries[ndx].size = sizeof(deInt32);
+ }
+
+ specConstantEntries.push_back(entries);
+
+ specInfo.mapEntryCount = (deUint32)numSpecConstants;
+ specInfo.pMapEntries = specConstantEntries.back().data();
+ specInfo.dataSize = numSpecConstants * sizeof(deInt32);
+ specInfo.pData = stageIt->second.data();
+ specializationInfos.push_back(specInfo);
+
+ stageInfo->pSpecializationInfo = &specializationInfos.back();
+ }
+ }
const VkPipelineDepthStencilStateCreateInfo depthStencilParams =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
0.0f, // float slopeScaledDepthBias;
1.0f, // float lineWidth;
};
+ const VkPrimitiveTopology topology = instance.hasTessellation? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyParams =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineInputAssemblyStateCreateFlags)0,
- VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // VkPrimitiveTopology topology;
+ topology, // VkPrimitiveTopology topology;
DE_FALSE, // deUint32 primitiveRestartEnable;
};
const VkVertexInputBindingDescription vertexBinding0 =
3u
};
+ const VkPipelineTessellationStateCreateInfo* tessellationInfo = instance.hasTessellation? &tessellationState: DE_NULL;
const VkGraphicsPipelineCreateInfo pipelineParams =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
&shaderStageParams[0], // const VkPipelineShaderStageCreateInfo* pStages;
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
&inputAssemblyParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
- &tessellationState, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ tessellationInfo, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
&multisampleParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
return TestStatus::pass("Rendered output matches input");
}
-void createTestsForAllStages(const std::string& name,
- const RGBA (&inputColors)[4],
- const RGBA (&outputColors)[4],
- const map<string, string>& testCodeFragments,
- tcu::TestCaseGroup* tests)
+void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const vector<deInt32>& specConstants, tcu::TestCaseGroup* tests)
{
const ShaderElement pipelineStages[] =
{
ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
};
+ StageToSpecConstantMap specConstantMap;
+
+ specConstantMap[VK_SHADER_STAGE_VERTEX_BIT] = specConstants;
addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-vert", "", addShaderCodeCustomVertex, runAndVerifyDefaultPipeline,
- createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+ createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+ specConstantMap.clear();
+ specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants;
addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
- createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+ createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+ specConstantMap.clear();
+ specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants;
addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
- createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+ createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+ specConstantMap.clear();
+ specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants;
addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
- createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+ createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+ specConstantMap.clear();
+ specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants;
addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
- createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+ createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+}
+
+inline void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, tcu::TestCaseGroup* tests)
+{
+ vector<deInt32> noSpecConstants;
+ createTestsForAllStages(name, inputColors, outputColors, testCodeFragments, noSpecConstants, tests);
}
+
} // anonymous
-tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
+tcu::TestCaseGroup* createOpSourceTests (tcu::TestContext& testCtx)
+{
+ struct NameCodePair { string name, code; };
+ RGBA defaultColors[4];
+ de::MovePtr<tcu::TestCaseGroup> opSourceTests (new tcu::TestCaseGroup(testCtx, "opsource", "OpSource instruction"));
+ const std::string opsourceGLSLWithFile = "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile ";
+ map<string, string> fragments = passthruFragments();
+ const NameCodePair tests[] =
+ {
+ {"unknown", "OpSource Unknown 321"},
+ {"essl", "OpSource ESSL 310"},
+ {"glsl", "OpSource GLSL 450"},
+ {"opencl_cpp", "OpSource OpenCL_CPP 120"},
+ {"opencl_c", "OpSource OpenCL_C 120"},
+ {"multiple", "OpSource GLSL 450\nOpSource GLSL 450"},
+ {"file", opsourceGLSLWithFile},
+ {"source", opsourceGLSLWithFile + "\"void main(){}\""},
+ // Longest possible source string: SPIR-V limits instructions to 65535
+ // words, of which the first 4 are opsourceGLSLWithFile; the rest will
+ // contain 65530 UTF8 characters (one word each) plus one last word
+ // containing 3 ASCII characters and \0.
+ {"longsource", opsourceGLSLWithFile + '"' + makeLongUTF8String(65530) + "ccc" + '"'}
+ };
+
+ getDefaultColors(defaultColors);
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+ {
+ fragments["debug"] = tests[testNdx].code;
+ createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
+ }
+
+ return opSourceTests.release();
+}
+
+tcu::TestCaseGroup* createOpSourceContinuedTests (tcu::TestContext& testCtx)
+{
+ struct NameCodePair { string name, code; };
+ RGBA defaultColors[4];
+ de::MovePtr<tcu::TestCaseGroup> opSourceTests (new tcu::TestCaseGroup(testCtx, "opsourcecontinued", "OpSourceContinued instruction"));
+ map<string, string> fragments = passthruFragments();
+ const std::string opsource = "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile \"void main(){}\"\n";
+ const NameCodePair tests[] =
+ {
+ {"empty", opsource + "OpSourceContinued \"\""},
+ {"short", opsource + "OpSourceContinued \"abcde\""},
+ {"multiple", opsource + "OpSourceContinued \"abcde\"\nOpSourceContinued \"fghij\""},
+ // Longest possible source string: SPIR-V limits instructions to 65535
+ // words, of which the first one is OpSourceContinued/length; the rest
+ // will contain 65533 UTF8 characters (one word each) plus one last word
+ // containing 3 ASCII characters and \0.
+ {"long", opsource + "OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\""}
+ };
+
+ getDefaultColors(defaultColors);
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+ {
+ fragments["debug"] = tests[testNdx].code;
+ createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
+ }
+
+ return opSourceTests.release();
+}
+
+tcu::TestCaseGroup* createOpNoLineTests(tcu::TestContext& testCtx)
{
- de::MovePtr<tcu::TestCaseGroup> instructionTests (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
-
- instructionTests->addChild(createOpNopGroup(testCtx));
- instructionTests->addChild(createOpLineGroup(testCtx));
- instructionTests->addChild(createOpNoLineGroup(testCtx));
- instructionTests->addChild(createOpConstantNullGroup(testCtx));
- instructionTests->addChild(createOpConstantCompositeGroup(testCtx));
- instructionTests->addChild(createOpConstantUsageGroup(testCtx));
- instructionTests->addChild(createOpSourceGroup(testCtx));
- instructionTests->addChild(createOpSourceExtensionGroup(testCtx));
- instructionTests->addChild(createDecorationGroupGroup(testCtx));
- instructionTests->addChild(createOpPhiGroup(testCtx));
- instructionTests->addChild(createLoopControlGroup(testCtx));
- instructionTests->addChild(createFunctionControlGroup(testCtx));
- instructionTests->addChild(createSelectionControlGroup(testCtx));
- instructionTests->addChild(createBlockOrderGroup(testCtx));
- instructionTests->addChild(createOpUndefGroup(testCtx));
- instructionTests->addChild(createOpUnreachableGroup(testCtx));
-
- RGBA defaultColors[4];
+ RGBA defaultColors[4];
+ de::MovePtr<tcu::TestCaseGroup> opLineTests (new tcu::TestCaseGroup(testCtx, "opNoLine", "OpNoLine instruction"));
+ map<string, string> fragments;
getDefaultColors(defaultColors);
- de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "graphics-assembly", "Test the graphics pipeline"));
- createTestsForAllStages("passthru", defaultColors, defaultColors, passthruFragments(), group.get());
- instructionTests->addChild(group.release());
+ fragments["debug"] =
+ "%name = OpString \"name\"\n";
+
+ fragments["pre_main"] =
+ "OpNoLine\n"
+ "OpNoLine\n"
+ "OpLine %name 1 1\n"
+ "OpNoLine\n"
+ "OpLine %name 1 1\n"
+ "OpLine %name 1 1\n"
+ "%second_function = OpFunction %v4f32 None %v4f32_function\n"
+ "OpNoLine\n"
+ "OpLine %name 1 1\n"
+ "OpNoLine\n"
+ "OpLine %name 1 1\n"
+ "OpLine %name 1 1\n"
+ "%second_param1 = OpFunctionParameter %v4f32\n"
+ "OpNoLine\n"
+ "OpNoLine\n"
+ "%label_secondfunction = OpLabel\n"
+ "OpNoLine\n"
+ "OpReturnValue %second_param1\n"
+ "OpFunctionEnd\n"
+ "OpNoLine\n"
+ "OpNoLine\n";
+
+ fragments["testfun"] =
+ // A %test_code function that returns its argument unchanged.
+ "OpNoLine\n"
+ "OpNoLine\n"
+ "OpLine %name 1 1\n"
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "OpNoLine\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "OpNoLine\n"
+ "OpNoLine\n"
+ "%label_testfun = OpLabel\n"
+ "OpNoLine\n"
+ "%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
+ "OpReturnValue %val1\n"
+ "OpFunctionEnd\n"
+ "OpLine %name 1 1\n"
+ "OpNoLine\n";
+
+ createTestsForAllStages("opNoLine", defaultColors, defaultColors, fragments, opLineTests.get());
+
+ return opLineTests.release();
+}
+
+
+tcu::TestCaseGroup* createOpLineTests(tcu::TestContext& testCtx)
+{
+ RGBA defaultColors[4];
+ de::MovePtr<tcu::TestCaseGroup> opLineTests (new tcu::TestCaseGroup(testCtx, "opLine", "OpLine instruction"));
+ map<string, string> fragments;
+ std::vector<std::pair<std::string, std::string> > problemStrings;
+
+ problemStrings.push_back(std::make_pair<std::string, std::string>("empty_name", ""));
+ problemStrings.push_back(std::make_pair<std::string, std::string>("short_name", "short_name"));
+ problemStrings.push_back(std::make_pair<std::string, std::string>("long_name", makeLongUTF8String(65530) + "ccc"));
+ getDefaultColors(defaultColors);
+
+ fragments["debug"] =
+ "%other_name = OpString \"other_name\"\n";
+
+ fragments["pre_main"] =
+ "OpLine %file_name 32 0\n"
+ "OpLine %file_name 32 32\n"
+ "OpLine %file_name 32 40\n"
+ "OpLine %other_name 32 40\n"
+ "OpLine %other_name 0 100\n"
+ "OpLine %other_name 0 4294967295\n"
+ "OpLine %other_name 4294967295 0\n"
+ "OpLine %other_name 32 40\n"
+ "OpLine %file_name 0 0\n"
+ "%second_function = OpFunction %v4f32 None %v4f32_function\n"
+ "OpLine %file_name 1 0\n"
+ "%second_param1 = OpFunctionParameter %v4f32\n"
+ "OpLine %file_name 1 3\n"
+ "OpLine %file_name 1 2\n"
+ "%label_secondfunction = OpLabel\n"
+ "OpLine %file_name 0 2\n"
+ "OpReturnValue %second_param1\n"
+ "OpFunctionEnd\n"
+ "OpLine %file_name 0 2\n"
+ "OpLine %file_name 0 2\n";
+
+ fragments["testfun"] =
+ // A %test_code function that returns its argument unchanged.
+ "OpLine %file_name 1 0\n"
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "OpLine %file_name 16 330\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "OpLine %file_name 14 442\n"
+ "%label_testfun = OpLabel\n"
+ "OpLine %file_name 11 1024\n"
+ "%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
+ "OpLine %file_name 2 97\n"
+ "OpReturnValue %val1\n"
+ "OpFunctionEnd\n"
+ "OpLine %file_name 5 32\n";
+
+ for (size_t i = 0; i < problemStrings.size(); ++i)
+ {
+ map<string, string> testFragments = fragments;
+ testFragments["debug"] += "%file_name = OpString \"" + problemStrings[i].second + "\"\n";
+ createTestsForAllStages(string("opLine") + "-" + problemStrings[i].first, defaultColors, defaultColors, testFragments, opLineTests.get());
+ }
+
+ return opLineTests.release();
+}
+
+tcu::TestCaseGroup* createOpConstantNullTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> opConstantNullTests (new tcu::TestCaseGroup(testCtx, "opConstantNull", "OpConstantNull instruction"));
+ RGBA colors[4];
+
+
+ const char functionStart[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n";
+
+ const char functionEnd[] =
+ "OpReturnValue %transformed_param\n"
+ "OpFunctionEnd\n";
+
+ struct NameConstantsCode
+ {
+ string name;
+ string constants;
+ string code;
+ };
+
+ NameConstantsCode tests[] =
+ {
+ {
+ "vec4",
+ "%cnull = OpConstantNull %v4f32\n",
+ "%transformed_param = OpFAdd %v4f32 %param1 %cnull\n"
+ },
+ {
+ "float",
+ "%cnull = OpConstantNull %f32\n",
+ "%vp = OpVariable %fp_v4f32 Function\n"
+ "%v = OpLoad %v4f32 %vp\n"
+ "%v0 = OpVectorInsertDynamic %v4f32 %v %cnull %c_i32_0\n"
+ "%v1 = OpVectorInsertDynamic %v4f32 %v0 %cnull %c_i32_1\n"
+ "%v2 = OpVectorInsertDynamic %v4f32 %v1 %cnull %c_i32_2\n"
+ "%v3 = OpVectorInsertDynamic %v4f32 %v2 %cnull %c_i32_3\n"
+ "%transformed_param = OpFAdd %v4f32 %param1 %v3\n"
+ },
+ {
+ "bool",
+ "%cnull = OpConstantNull %bool\n",
+ "%v = OpVariable %fp_v4f32 Function\n"
+ " OpStore %v %param1\n"
+ " OpSelectionMerge %false_label None\n"
+ " OpBranchConditional %cnull %true_label %false_label\n"
+ "%true_label = OpLabel\n"
+ " OpStore %v %c_v4f32_0_5_0_5_0_5_0_5\n"
+ " OpBranch %false_label\n"
+ "%false_label = OpLabel\n"
+ "%transformed_param = OpLoad %v4f32 %v\n"
+ },
+ {
+ "i32",
+ "%cnull = OpConstantNull %i32\n",
+ "%v = OpVariable %fp_v4f32 Function %c_v4f32_0_5_0_5_0_5_0_5\n"
+ "%b = OpIEqual %bool %cnull %c_i32_0\n"
+ " OpSelectionMerge %false_label None\n"
+ " OpBranchConditional %b %true_label %false_label\n"
+ "%true_label = OpLabel\n"
+ " OpStore %v %param1\n"
+ " OpBranch %false_label\n"
+ "%false_label = OpLabel\n"
+ "%transformed_param = OpLoad %v4f32 %v\n"
+ },
+ {
+ "struct",
+ "%stype = OpTypeStruct %f32 %v4f32\n"
+ "%fp_stype = OpTypePointer Function %stype\n"
+ "%cnull = OpConstantNull %stype\n",
+ "%v = OpVariable %fp_stype Function %cnull\n"
+ "%f = OpAccessChain %fp_v4f32 %v %c_i32_1\n"
+ "%f_val = OpLoad %v4f32 %f\n"
+ "%transformed_param = OpFAdd %v4f32 %param1 %f_val\n"
+ },
+ {
+ "array",
+ "%a4_v4f32 = OpTypeArray %v4f32 %c_u32_4\n"
+ "%fp_a4_v4f32 = OpTypePointer Function %a4_v4f32\n"
+ "%cnull = OpConstantNull %a4_v4f32\n",
+ "%v = OpVariable %fp_a4_v4f32 Function %cnull\n"
+ "%f = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
+ "%f1 = OpAccessChain %fp_v4f32 %v %c_u32_1\n"
+ "%f2 = OpAccessChain %fp_v4f32 %v %c_u32_2\n"
+ "%f3 = OpAccessChain %fp_v4f32 %v %c_u32_3\n"
+ "%f_val = OpLoad %v4f32 %f\n"
+ "%f1_val = OpLoad %v4f32 %f1\n"
+ "%f2_val = OpLoad %v4f32 %f2\n"
+ "%f3_val = OpLoad %v4f32 %f3\n"
+ "%t0 = OpFAdd %v4f32 %param1 %f_val\n"
+ "%t1 = OpFAdd %v4f32 %t0 %f1_val\n"
+ "%t2 = OpFAdd %v4f32 %t1 %f2_val\n"
+ "%transformed_param = OpFAdd %v4f32 %t2 %f3_val\n"
+ },
+ {
+ "matrix",
+ "%mat4x4_f32 = OpTypeMatrix %v4f32 4\n"
+ "%cnull = OpConstantNull %mat4x4_f32\n",
+ // Our null matrix * any vector should result in a zero vector.
+ "%v = OpVectorTimesMatrix %v4f32 %param1 %cnull\n"
+ "%transformed_param = OpFAdd %v4f32 %param1 %v\n"
+ }
+ };
+
+ getHalfColorsFullAlpha(colors);
+
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
+ {
+ map<string, string> fragments;
+ fragments["pre_main"] = tests[testNdx].constants;
+ fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
+ createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, opConstantNullTests.get());
+ }
+ return opConstantNullTests.release();
+}
+tcu::TestCaseGroup* createOpConstantCompositeTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> opConstantCompositeTests (new tcu::TestCaseGroup(testCtx, "opConstantComposite", "OpConstantComposite instruction"));
+ RGBA inputColors[4];
+ RGBA outputColors[4];
+
+
+ const char functionStart[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n";
+
+ const char functionEnd[] =
+ "OpReturnValue %transformed_param\n"
+ "OpFunctionEnd\n";
+
+ struct NameConstantsCode
+ {
+ string name;
+ string constants;
+ string code;
+ };
+
+ NameConstantsCode tests[] =
+ {
+ {
+ "vec4",
+
+ "%cval = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0\n",
+ "%transformed_param = OpFAdd %v4f32 %param1 %cval\n"
+ },
+ {
+ "struct",
+
+ "%stype = OpTypeStruct %v4f32 %f32\n"
+ "%fp_stype = OpTypePointer Function %stype\n"
+ "%f32_n_1 = OpConstant %f32 -1.0\n"
+ "%f32_1_5 = OpConstant %f32 !0x3fc00000\n" // +1.5
+ "%cvec = OpConstantComposite %v4f32 %f32_1_5 %f32_1_5 %f32_1_5 %c_f32_1\n"
+ "%cval = OpConstantComposite %stype %cvec %f32_n_1\n",
+
+ "%v = OpVariable %fp_stype Function %cval\n"
+ "%vec_ptr = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
+ "%f32_ptr = OpAccessChain %fp_v4f32 %v %c_u32_1\n"
+ "%vec_val = OpLoad %v4f32 %vec_ptr\n"
+ "%f32_val = OpLoad %v4f32 %f32_ptr\n"
+ "%tmp1 = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_1 %f32_val\n" // vec4(-1)
+ "%tmp2 = OpFAdd %v4f32 %tmp1 %param1\n" // param1 + vec4(-1)
+ "%transformed_param = OpFAdd %v4f32 %tmp2 %vec_val\n" // param1 + vec4(-1) + vec4(1.5, 1.5, 1.5, 1.0)
+ },
+ {
+ // [1|0|0|0.5] [x] = x + 0.5
+ // [0|1|0|0.5] [y] = y + 0.5
+ // [0|0|1|0.5] [z] = z + 0.5
+ // [0|0|0|1 ] [1] = 1
+ "matrix",
+
+ "%mat4x4_f32 = OpTypeMatrix %v4f32 4\n"
+ "%v4f32_1_0_0_0 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_0\n"
+ "%v4f32_0_1_0_0 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_1 %c_f32_0 %c_f32_0\n"
+ "%v4f32_0_0_1_0 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_1 %c_f32_0\n"
+ "%v4f32_0_5_0_5_0_5_1 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_1\n"
+ "%cval = OpConstantComposite %mat4x4_f32 %v4f32_1_0_0_0 %v4f32_0_1_0_0 %v4f32_0_0_1_0 %v4f32_0_5_0_5_0_5_1\n",
+
+ "%transformed_param = OpMatrixTimesVector %v4f32 %cval %param1\n"
+ },
+ {
+ "array",
+
+ "%c_v4f32_1_1_1_0 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%fp_a4f32 = OpTypePointer Function %a4f32\n"
+ "%f32_n_1 = OpConstant %f32 -1.0\n"
+ "%f32_1_5 = OpConstant %f32 !0x3fc00000\n" // +1.5
+ "%carr = OpConstantComposite %a4f32 %c_f32_0 %f32_n_1 %f32_1_5 %c_f32_0\n",
+
+ "%v = OpVariable %fp_a4f32 Function %carr\n"
+ "%f = OpAccessChain %fp_f32 %v %c_u32_0\n"
+ "%f1 = OpAccessChain %fp_f32 %v %c_u32_1\n"
+ "%f2 = OpAccessChain %fp_f32 %v %c_u32_2\n"
+ "%f3 = OpAccessChain %fp_f32 %v %c_u32_3\n"
+ "%f_val = OpLoad %f32 %f\n"
+ "%f1_val = OpLoad %f32 %f1\n"
+ "%f2_val = OpLoad %f32 %f2\n"
+ "%f3_val = OpLoad %f32 %f3\n"
+ "%ftot1 = OpFAdd %f32 %f_val %f1_val\n"
+ "%ftot2 = OpFAdd %f32 %ftot1 %f2_val\n"
+ "%ftot3 = OpFAdd %f32 %ftot2 %f3_val\n" // 0 - 1 + 1.5 + 0
+ "%add_vec = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %ftot3\n"
+ "%transformed_param = OpFAdd %v4f32 %param1 %add_vec\n"
+ },
+ {
+ //
+ // [
+ // {
+ // 0.0,
+ // [ 1.0, 1.0, 1.0, 1.0]
+ // },
+ // {
+ // 1.0,
+ // [ 0.0, 0.5, 0.0, 0.0]
+ // }, // ^^^
+ // {
+ // 0.0,
+ // [ 1.0, 1.0, 1.0, 1.0]
+ // }
+ // ]
+ "array_of_struct_of_array",
+
+ "%c_v4f32_1_1_1_0 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+ "%fp_a4f32 = OpTypePointer Function %a4f32\n"
+ "%stype = OpTypeStruct %f32 %a4f32\n"
+ "%a3stype = OpTypeArray %stype %c_u32_3\n"
+ "%fp_a3stype = OpTypePointer Function %a3stype\n"
+ "%ca4f32_0 = OpConstantComposite %a4f32 %c_f32_0 %c_f32_0_5 %c_f32_0 %c_f32_0\n"
+ "%ca4f32_1 = OpConstantComposite %a4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+ "%cstype1 = OpConstantComposite %stype %c_f32_0 %ca4f32_1\n"
+ "%cstype2 = OpConstantComposite %stype %c_f32_1 %ca4f32_0\n"
+ "%carr = OpConstantComposite %a3stype %cstype1 %cstype2 %cstype1",
+
+ "%v = OpVariable %fp_a3stype Function %carr\n"
+ "%f = OpAccessChain %fp_f32 %v %c_u32_1 %c_u32_1 %c_u32_1\n"
+ "%add_vec = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %f\n"
+ "%transformed_param = OpFAdd %v4f32 %param1 %add_vec\n"
+ }
+ };
+
+ getHalfColorsFullAlpha(inputColors);
+ outputColors[0] = RGBA(255, 255, 255, 255);
+ outputColors[1] = RGBA(255, 127, 127, 255);
+ outputColors[2] = RGBA(127, 255, 127, 255);
+ outputColors[3] = RGBA(127, 127, 255, 255);
+
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
+ {
+ map<string, string> fragments;
+ fragments["pre_main"] = tests[testNdx].constants;
+ fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
+ createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, opConstantCompositeTests.get());
+ }
+ return opConstantCompositeTests.release();
+}
+
+tcu::TestCaseGroup* createSelectionBlockOrderTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "selection_block_order", "Out-of-order blocks for selection"));
+ RGBA inputColors[4];
+ RGBA outputColors[4];
+ map<string, string> fragments;
+
+ // vec4 test_code(vec4 param) {
+ // vec4 result = param;
+ // for (int i = 0; i < 4; ++i) {
+ // if (i == 0) result[i] = 0.;
+ // else result[i] = 1. - result[i];
+ // }
+ // return result;
+ // }
+ const char function[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n"
+ "%iptr = OpVariable %fp_i32 Function\n"
+ " OpStore %iptr %c_i32_0\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param1\n"
+ " OpBranch %loop\n"
+
+ // Loop entry block.
+ "%loop = OpLabel\n"
+ "%ival = OpLoad %i32 %iptr\n"
+ "%lt_4 = OpSLessThan %bool %ival %c_i32_4\n"
+ " OpLoopMerge %exit %loop None\n"
+ " OpBranchConditional %lt_4 %if_entry %exit\n"
+
+ // Merge block for loop.
+ "%exit = OpLabel\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+
+ // If-statement entry block.
+ "%if_entry = OpLabel\n"
+ "%loc = OpAccessChain %fp_f32 %result %ival\n"
+ "%eq_0 = OpIEqual %bool %ival %c_i32_0\n"
+ " OpSelectionMerge %if_exit None\n"
+ " OpBranchConditional %eq_0 %if_true %if_false\n"
+
+ // False branch for if-statement.
+ "%if_false = OpLabel\n"
+ "%val = OpLoad %f32 %loc\n"
+ "%sub = OpFSub %f32 %c_f32_1 %val\n"
+ " OpStore %loc %sub\n"
+ " OpBranch %if_exit\n"
+
+ // Merge block for if-statement.
+ "%if_exit = OpLabel\n"
+ "%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
+ " OpStore %iptr %ival_next\n"
+ " OpBranch %loop\n"
+
+ // True branch for if-statement.
+ "%if_true = OpLabel\n"
+ " OpStore %loc %c_f32_0\n"
+ " OpBranch %if_exit\n"
+
+ " OpFunctionEnd\n";
+
+ fragments["testfun"] = function;
+
+ inputColors[0] = RGBA(127, 127, 127, 0);
+ inputColors[1] = RGBA(127, 0, 0, 0);
+ inputColors[2] = RGBA(0, 127, 0, 0);
+ inputColors[3] = RGBA(0, 0, 127, 0);
+
+ outputColors[0] = RGBA(0, 128, 128, 255);
+ outputColors[1] = RGBA(0, 255, 255, 255);
+ outputColors[2] = RGBA(0, 128, 255, 255);
+ outputColors[3] = RGBA(0, 255, 128, 255);
+
+ createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createSwitchBlockOrderTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "switch_block_order", "Out-of-order blocks for switch"));
+ RGBA inputColors[4];
+ RGBA outputColors[4];
+ map<string, string> fragments;
+
+ const char typesAndConstants[] =
+ "%c_f32_p2 = OpConstant %f32 0.2\n"
+ "%c_f32_p4 = OpConstant %f32 0.4\n"
+ "%c_f32_p6 = OpConstant %f32 0.6\n"
+ "%c_f32_p8 = OpConstant %f32 0.8\n";
+
+ // vec4 test_code(vec4 param) {
+ // vec4 result = param;
+ // for (int i = 0; i < 4; ++i) {
+ // switch (i) {
+ // case 0: result[i] += .2; break;
+ // case 1: result[i] += .6; break;
+ // case 2: result[i] += .4; break;
+ // case 3: result[i] += .8; break;
+ // default: break; // unreachable
+ // }
+ // }
+ // return result;
+ // }
+ const char function[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n"
+ "%iptr = OpVariable %fp_i32 Function\n"
+ " OpStore %iptr %c_i32_0\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param1\n"
+ " OpBranch %loop\n"
+
+ // Loop entry block.
+ "%loop = OpLabel\n"
+ "%ival = OpLoad %i32 %iptr\n"
+ "%lt_4 = OpSLessThan %bool %ival %c_i32_4\n"
+ " OpLoopMerge %exit %loop None\n"
+ " OpBranchConditional %lt_4 %switch_entry %exit\n"
+
+ // Merge block for loop.
+ "%exit = OpLabel\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+
+ // Switch-statement entry block.
+ "%switch_entry = OpLabel\n"
+ "%loc = OpAccessChain %fp_f32 %result %ival\n"
+ "%val = OpLoad %f32 %loc\n"
+ " OpSelectionMerge %switch_exit None\n"
+ " OpSwitch %ival %switch_default 0 %case0 1 %case1 2 %case2 3 %case3\n"
+
+ "%case2 = OpLabel\n"
+ "%addp4 = OpFAdd %f32 %val %c_f32_p4\n"
+ " OpStore %loc %addp4\n"
+ " OpBranch %switch_exit\n"
+
+ "%switch_default = OpLabel\n"
+ " OpUnreachable\n"
+
+ "%case3 = OpLabel\n"
+ "%addp8 = OpFAdd %f32 %val %c_f32_p8\n"
+ " OpStore %loc %addp8\n"
+ " OpBranch %switch_exit\n"
+
+ "%case0 = OpLabel\n"
+ "%addp2 = OpFAdd %f32 %val %c_f32_p2\n"
+ " OpStore %loc %addp2\n"
+ " OpBranch %switch_exit\n"
+
+ // Merge block for switch-statement.
+ "%switch_exit = OpLabel\n"
+ "%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
+ " OpStore %iptr %ival_next\n"
+ " OpBranch %loop\n"
+
+ "%case1 = OpLabel\n"
+ "%addp6 = OpFAdd %f32 %val %c_f32_p6\n"
+ " OpStore %loc %addp6\n"
+ " OpBranch %switch_exit\n"
+
+ " OpFunctionEnd\n";
+
+ fragments["pre_main"] = typesAndConstants;
+ fragments["testfun"] = function;
+
+ inputColors[0] = RGBA(127, 27, 127, 51);
+ inputColors[1] = RGBA(127, 0, 0, 51);
+ inputColors[2] = RGBA(0, 27, 0, 51);
+ inputColors[3] = RGBA(0, 0, 127, 51);
+
+ outputColors[0] = RGBA(178, 180, 229, 255);
+ outputColors[1] = RGBA(178, 153, 102, 255);
+ outputColors[2] = RGBA(51, 180, 102, 255);
+ outputColors[3] = RGBA(51, 153, 229, 255);
+
+ createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createDecorationGroupTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "decoration_group", "Decoration group tests"));
+ RGBA inputColors[4];
+ RGBA outputColors[4];
+ map<string, string> fragments;
+
+ const char decorations[] =
+ "OpDecorate %array_group ArrayStride 4\n"
+ "OpDecorate %struct_member_group Offset 0\n"
+ "%array_group = OpDecorationGroup\n"
+ "%struct_member_group = OpDecorationGroup\n"
+
+ "OpDecorate %group1 RelaxedPrecision\n"
+ "OpDecorate %group3 RelaxedPrecision\n"
+ "OpDecorate %group3 Invariant\n"
+ "OpDecorate %group3 Restrict\n"
+ "%group0 = OpDecorationGroup\n"
+ "%group1 = OpDecorationGroup\n"
+ "%group3 = OpDecorationGroup\n";
+
+ const char typesAndConstants[] =
+ "%a3f32 = OpTypeArray %f32 %c_u32_3\n"
+ "%struct1 = OpTypeStruct %a3f32\n"
+ "%struct2 = OpTypeStruct %a3f32\n"
+ "%fp_struct1 = OpTypePointer Function %struct1\n"
+ "%fp_struct2 = OpTypePointer Function %struct2\n"
+ "%c_f32_2 = OpConstant %f32 2.\n"
+ "%c_f32_n2 = OpConstant %f32 -2.\n"
+
+ "%c_a3f32_1 = OpConstantComposite %a3f32 %c_f32_1 %c_f32_2 %c_f32_1\n"
+ "%c_a3f32_2 = OpConstantComposite %a3f32 %c_f32_n1 %c_f32_n2 %c_f32_n1\n"
+ "%c_struct1 = OpConstantComposite %struct1 %c_a3f32_1\n"
+ "%c_struct2 = OpConstantComposite %struct2 %c_a3f32_2\n";
+
+ const char function[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%entry = OpLabel\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param\n"
+ "%v_struct1 = OpVariable %fp_struct1 Function\n"
+ " OpStore %v_struct1 %c_struct1\n"
+ "%v_struct2 = OpVariable %fp_struct2 Function\n"
+ " OpStore %v_struct2 %c_struct2\n"
+ "%ptr1 = OpAccessChain %fp_f32 %v_struct1 %c_i32_0 %c_i32_1\n"
+ "%val1 = OpLoad %f32 %ptr1\n"
+ "%ptr2 = OpAccessChain %fp_f32 %v_struct2 %c_i32_0 %c_i32_2\n"
+ "%val2 = OpLoad %f32 %ptr2\n"
+ "%addvalues = OpFAdd %f32 %val1 %val2\n"
+ "%ptr = OpAccessChain %fp_f32 %result %c_i32_1\n"
+ "%val = OpLoad %f32 %ptr\n"
+ "%addresult = OpFAdd %f32 %addvalues %val\n"
+ " OpStore %ptr %addresult\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+ " OpFunctionEnd\n";
+
+ struct CaseNameDecoration
+ {
+ string name;
+ string decoration;
+ };
+
+ CaseNameDecoration tests[] =
+ {
+ {
+ "same_decoration_group_on_multiple_types",
+ "OpGroupMemberDecorate %struct_member_group %struct1 0 %struct2 0\n"
+ },
+ {
+ "empty_decoration_group",
+ "OpGroupDecorate %group0 %a3f32\n"
+ "OpGroupDecorate %group0 %result\n"
+ },
+ {
+ "one_element_decoration_group",
+ "OpGroupDecorate %array_group %a3f32\n"
+ },
+ {
+ "multiple_elements_decoration_group",
+ "OpGroupDecorate %group3 %v_struct1\n"
+ },
+ {
+ "multiple_decoration_groups_on_same_variable",
+ "OpGroupDecorate %group0 %v_struct2\n"
+ "OpGroupDecorate %group1 %v_struct2\n"
+ "OpGroupDecorate %group3 %v_struct2\n"
+ },
+ {
+ "same_decoration_group_multiple_times",
+ "OpGroupDecorate %group1 %addvalues\n"
+ "OpGroupDecorate %group1 %addvalues\n"
+ "OpGroupDecorate %group1 %addvalues\n"
+ },
+
+ };
+
+ getHalfColorsFullAlpha(inputColors);
+ getHalfColorsFullAlpha(outputColors);
+
+ for (size_t idx = 0; idx < (sizeof(tests) / sizeof(tests[0])); ++idx)
+ {
+ fragments["decoration"] = decorations + tests[idx].decoration;
+ fragments["pre_main"] = typesAndConstants;
+ fragments["testfun"] = function;
+
+ createTestsForAllStages(tests[idx].name, inputColors, outputColors, fragments, group.get());
+ }
+
+ return group.release();
+}
+
+struct SpecConstantTwoIntGraphicsCase
+{
+ const char* caseName;
+ const char* scDefinition0;
+ const char* scDefinition1;
+ const char* scResultType;
+ const char* scOperation;
+ deInt32 scActualValue0;
+ deInt32 scActualValue1;
+ const char* resultOperation;
+ RGBA expectedColors[4];
+
+ SpecConstantTwoIntGraphicsCase (const char* name,
+ const char* definition0,
+ const char* definition1,
+ const char* resultType,
+ const char* operation,
+ deInt32 value0,
+ deInt32 value1,
+ const char* resultOp,
+ const RGBA (&output)[4])
+ : caseName (name)
+ , scDefinition0 (definition0)
+ , scDefinition1 (definition1)
+ , scResultType (resultType)
+ , scOperation (operation)
+ , scActualValue0 (value0)
+ , scActualValue1 (value1)
+ , resultOperation (resultOp)
+ {
+ expectedColors[0] = output[0];
+ expectedColors[1] = output[1];
+ expectedColors[2] = output[2];
+ expectedColors[3] = output[3];
+ }
+};
+
+tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
+ vector<SpecConstantTwoIntGraphicsCase> cases;
+ RGBA inputColors[4];
+ RGBA outputColors0[4];
+ RGBA outputColors1[4];
+ RGBA outputColors2[4];
+
+ const char decorations1[] =
+ "OpDecorate %sc_0 SpecId 0\n"
+ "OpDecorate %sc_1 SpecId 1\n";
+
+ const char typesAndConstants1[] =
+ "%sc_0 = OpSpecConstant${SC_DEF0}\n"
+ "%sc_1 = OpSpecConstant${SC_DEF1}\n"
+ "%sc_op = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n";
+
+ const char function1[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%label = OpLabel\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param\n"
+ "%gen = ${GEN_RESULT}\n"
+ "%index = OpIAdd %i32 %gen %c_i32_1\n"
+ "%loc = OpAccessChain %fp_f32 %result %index\n"
+ "%val = OpLoad %f32 %loc\n"
+ "%add = OpFAdd %f32 %val %c_f32_0_5\n"
+ " OpStore %loc %add\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+ " OpFunctionEnd\n";
+
+ inputColors[0] = RGBA(127, 127, 127, 255);
+ inputColors[1] = RGBA(127, 0, 0, 255);
+ inputColors[2] = RGBA(0, 127, 0, 255);
+ inputColors[3] = RGBA(0, 0, 127, 255);
+
+ // Derived from inputColors[x] by adding 128 to inputColors[x][0].
+ outputColors0[0] = RGBA(255, 127, 127, 255);
+ outputColors0[1] = RGBA(255, 0, 0, 255);
+ outputColors0[2] = RGBA(128, 127, 0, 255);
+ outputColors0[3] = RGBA(128, 0, 127, 255);
+
+ // Derived from inputColors[x] by adding 128 to inputColors[x][1].
+ outputColors1[0] = RGBA(127, 255, 127, 255);
+ outputColors1[1] = RGBA(127, 128, 0, 255);
+ outputColors1[2] = RGBA(0, 255, 0, 255);
+ outputColors1[3] = RGBA(0, 128, 127, 255);
+
+ // Derived from inputColors[x] by adding 128 to inputColors[x][2].
+ outputColors2[0] = RGBA(127, 127, 255, 255);
+ outputColors2[1] = RGBA(127, 0, 128, 255);
+ outputColors2[2] = RGBA(0, 127, 128, 255);
+ outputColors2[3] = RGBA(0, 0, 255, 255);
+
+ const char addZeroToSc[] = "OpIAdd %i32 %c_i32_0 %sc_op";
+ const char selectTrueUsingSc[] = "OpSelect %i32 %sc_op %c_i32_1 %c_i32_0";
+ const char selectFalseUsingSc[] = "OpSelect %i32 %sc_op %c_i32_0 %c_i32_1";
+
+ cases.push_back(SpecConstantTwoIntGraphicsCase("iadd", " %i32 0", " %i32 0", "%i32", "IAdd %sc_0 %sc_1", 19, -20, addZeroToSc, outputColors0));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("isub", " %i32 0", " %i32 0", "%i32", "ISub %sc_0 %sc_1", 19, 20, addZeroToSc, outputColors0));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("imul", " %i32 0", " %i32 0", "%i32", "IMul %sc_0 %sc_1", -1, -1, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("sdiv", " %i32 0", " %i32 0", "%i32", "SDiv %sc_0 %sc_1", -126, 126, addZeroToSc, outputColors0));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("udiv", " %i32 0", " %i32 0", "%i32", "UDiv %sc_0 %sc_1", 126, 126, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("srem", " %i32 0", " %i32 0", "%i32", "SRem %sc_0 %sc_1", -3, 2, addZeroToSc, outputColors0));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("smod", " %i32 0", " %i32 0", "%i32", "SMod %sc_0 %sc_1", -3, 2, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("umod", " %i32 0", " %i32 0", "%i32", "UMod %sc_0 %sc_1", 1001, 500, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseand", " %i32 0", " %i32 0", "%i32", "BitwiseAnd %sc_0 %sc_1", 0x33, 0x0d, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseor", " %i32 0", " %i32 0", "%i32", "BitwiseOr %sc_0 %sc_1", 0, 1, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("bitwisexor", " %i32 0", " %i32 0", "%i32", "BitwiseAnd %sc_0 %sc_1", 0x2e, 0x2f, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightlogical", " %i32 0", " %i32 0", "%i32", "ShiftRightLogical %sc_0 %sc_1", 2, 1, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightarithmetic", " %i32 0", " %i32 0", "%i32", "ShiftRightArithmetic %sc_0 %sc_1", -4, 2, addZeroToSc, outputColors0));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("shiftleftlogical", " %i32 0", " %i32 0", "%i32", "ShiftLeftLogical %sc_0 %sc_1", 1, 0, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("slessthan", " %i32 0", " %i32 0", "%bool", "SLessThan %sc_0 %sc_1", -20, -10, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthan", " %i32 0", " %i32 0", "%bool", "ULessThan %sc_0 %sc_1", 10, 20, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthan", " %i32 0", " %i32 0", "%bool", "SGreaterThan %sc_0 %sc_1", -1000, 50, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthan", " %i32 0", " %i32 0", "%bool", "UGreaterThan %sc_0 %sc_1", 10, 5, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("slessthanequal", " %i32 0", " %i32 0", "%bool", "SLessThanEqual %sc_0 %sc_1", -10, -10, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthanequal", " %i32 0", " %i32 0", "%bool", "ULessThanEqual %sc_0 %sc_1", 50, 100, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthanequal", " %i32 0", " %i32 0", "%bool", "SGreaterThanEqual %sc_0 %sc_1", -1000, 50, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthanequal", " %i32 0", " %i32 0", "%bool", "UGreaterThanEqual %sc_0 %sc_1", 10, 10, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("iequal", " %i32 0", " %i32 0", "%bool", "IEqual %sc_0 %sc_1", 42, 24, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("logicaland", "True %bool", "True %bool", "%bool", "LogicalAnd %sc_0 %sc_1", 0, 1, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("logicalor", "False %bool", "False %bool", "%bool", "LogicalOr %sc_0 %sc_1", 1, 0, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("logicalequal", "True %bool", "True %bool", "%bool", "LogicalEqual %sc_0 %sc_1", 0, 1, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnotequal", "False %bool", "False %bool", "%bool", "LogicalNotEqual %sc_0 %sc_1", 1, 0, selectTrueUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("snegate", " %i32 0", " %i32 0", "%i32", "SNegate %sc_0", -1, 0, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("not", " %i32 0", " %i32 0", "%i32", "Not %sc_0", -2, 0, addZeroToSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnot", "False %bool", "False %bool", "%bool", "LogicalNot %sc_0", 1, 0, selectFalseUsingSc, outputColors2));
+ cases.push_back(SpecConstantTwoIntGraphicsCase("select", "False %bool", " %i32 0", "%i32", "Select %sc_0 %sc_1 %c_i32_0", 1, 1, addZeroToSc, outputColors2));
+ // OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
+ // \todo[2015-12-1 antiagainst] OpQuantizeToF16
+
+ for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+ {
+ map<string, string> specializations;
+ map<string, string> fragments;
+ vector<deInt32> specConstants;
+
+ specializations["SC_DEF0"] = cases[caseNdx].scDefinition0;
+ specializations["SC_DEF1"] = cases[caseNdx].scDefinition1;
+ specializations["SC_RESULT_TYPE"] = cases[caseNdx].scResultType;
+ specializations["SC_OP"] = cases[caseNdx].scOperation;
+ specializations["GEN_RESULT"] = cases[caseNdx].resultOperation;
+
+ fragments["decoration"] = tcu::StringTemplate(decorations1).specialize(specializations);
+ fragments["pre_main"] = tcu::StringTemplate(typesAndConstants1).specialize(specializations);
+ fragments["testfun"] = tcu::StringTemplate(function1).specialize(specializations);
+
+ specConstants.push_back(cases[caseNdx].scActualValue0);
+ specConstants.push_back(cases[caseNdx].scActualValue1);
+
+ createTestsForAllStages(cases[caseNdx].caseName, inputColors, cases[caseNdx].expectedColors, fragments, specConstants, group.get());
+ }
+
+ const char decorations2[] =
+ "OpDecorate %sc_0 SpecId 0\n"
+ "OpDecorate %sc_1 SpecId 1\n"
+ "OpDecorate %sc_2 SpecId 2\n";
+
+ const char typesAndConstants2[] =
+ "%v3i32 = OpTypeVector %i32 3\n"
+
+ "%sc_0 = OpSpecConstant %i32 0\n"
+ "%sc_1 = OpSpecConstant %i32 0\n"
+ "%sc_2 = OpSpecConstant %i32 0\n"
+
+ "%vec3_0 = OpConstantComposite %v3i32 %c_i32_0 %c_i32_0 %c_i32_0\n"
+ "%sc_vec3_0 = OpSpecConstantOp %v3i32 CompositeInsert %sc_0 %vec3_0 0\n" // (sc_0, 0, 0)
+ "%sc_vec3_1 = OpSpecConstantOp %v3i32 CompositeInsert %sc_1 %vec3_0 1\n" // (0, sc_1, 0)
+ "%sc_vec3_2 = OpSpecConstantOp %v3i32 CompositeInsert %sc_2 %vec3_0 2\n" // (0, 0, sc_2)
+ "%sc_vec3_01 = OpSpecConstantOp %v3i32 VectorShuffle %sc_vec3_0 %sc_vec3_1 1 0 4\n" // (0, sc_0, sc_1)
+ "%sc_vec3_012 = OpSpecConstantOp %v3i32 VectorShuffle %sc_vec3_01 %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
+ "%sc_ext_0 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 0\n" // sc_2
+ "%sc_ext_1 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 1\n" // sc_0
+ "%sc_ext_2 = OpSpecConstantOp %i32 CompositeExtract %sc_vec3_012 2\n" // sc_1
+ "%sc_sub = OpSpecConstantOp %i32 ISub %sc_ext_0 %sc_ext_1\n" // (sc_2 - sc_0)
+ "%sc_final = OpSpecConstantOp %i32 IMul %sc_sub %sc_ext_2\n"; // (sc_2 - sc_0) * sc_1
+
+ const char function2[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%label = OpLabel\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param\n"
+ "%loc = OpAccessChain %fp_f32 %result %sc_final\n"
+ "%val = OpLoad %f32 %loc\n"
+ "%add = OpFAdd %f32 %val %c_f32_0_5\n"
+ " OpStore %loc %add\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+ " OpFunctionEnd\n";
+
+ map<string, string> fragments;
+ vector<deInt32> specConstants;
+
+ fragments["decoration"] = decorations2;
+ fragments["pre_main"] = typesAndConstants2;
+ fragments["testfun"] = function2;
+
+ specConstants.push_back(56789);
+ specConstants.push_back(-2);
+ specConstants.push_back(56788);
+
+ createTestsForAllStages("vector_related", inputColors, outputColors2, fragments, specConstants, group.get());
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createOpPhiTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
+ RGBA inputColors[4];
+ RGBA outputColors1[4];
+ RGBA outputColors2[4];
+ RGBA outputColors3[4];
+ map<string, string> fragments1;
+ map<string, string> fragments2;
+ map<string, string> fragments3;
+
+ const char typesAndConstants1[] =
+ "%c_f32_p2 = OpConstant %f32 0.2\n"
+ "%c_f32_p4 = OpConstant %f32 0.4\n"
+ "%c_f32_p6 = OpConstant %f32 0.6\n"
+ "%c_f32_p8 = OpConstant %f32 0.8\n";
+
+ // vec4 test_code(vec4 param) {
+ // vec4 result = param;
+ // for (int i = 0; i < 4; ++i) {
+ // float operand;
+ // switch (i) {
+ // case 0: operand = .2; break;
+ // case 1: operand = .6; break;
+ // case 2: operand = .4; break;
+ // case 3: operand = .0; break;
+ // default: break; // unreachable
+ // }
+ // result[i] += operand;
+ // }
+ // return result;
+ // }
+ const char function1[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n"
+ "%iptr = OpVariable %fp_i32 Function\n"
+ " OpStore %iptr %c_i32_0\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param1\n"
+ " OpBranch %loop\n"
+
+ "%loop = OpLabel\n"
+ "%ival = OpLoad %i32 %iptr\n"
+ "%lt_4 = OpSLessThan %bool %ival %c_i32_4\n"
+ " OpLoopMerge %exit %loop None\n"
+ " OpBranchConditional %lt_4 %entry %exit\n"
+
+ "%entry = OpLabel\n"
+ "%loc = OpAccessChain %fp_f32 %result %ival\n"
+ "%val = OpLoad %f32 %loc\n"
+ " OpSelectionMerge %phi None\n"
+ " OpSwitch %ival %default 0 %case0 1 %case1 2 %case2 3 %case3\n"
+
+ "%case0 = OpLabel\n"
+ " OpBranch %phi\n"
+ "%case1 = OpLabel\n"
+ " OpBranch %phi\n"
+ "%case2 = OpLabel\n"
+ " OpBranch %phi\n"
+ "%case3 = OpLabel\n"
+ " OpBranch %phi\n"
+
+ "%default = OpLabel\n"
+ " OpUnreachable\n"
+
+ "%phi = OpLabel\n"
+ "%operand = OpPhi %f32 %c_f32_p4 %case2 %c_f32_p6 %case1 %c_f32_p2 %case0 %c_f32_0 %case3\n" // not in the order of blocks
+ "%add = OpFAdd %f32 %val %operand\n"
+ " OpStore %loc %add\n"
+ "%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
+ " OpStore %iptr %ival_next\n"
+ " OpBranch %loop\n"
+
+ "%exit = OpLabel\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+
+ " OpFunctionEnd\n";
+
+ fragments1["pre_main"] = typesAndConstants1;
+ fragments1["testfun"] = function1;
+
+ getHalfColorsFullAlpha(inputColors);
+
+ outputColors1[0] = RGBA(178, 180, 229, 255);
+ outputColors1[1] = RGBA(178, 153, 102, 255);
+ outputColors1[2] = RGBA(51, 180, 102, 255);
+ outputColors1[3] = RGBA(51, 153, 229, 255);
+
+ createTestsForAllStages("out_of_order", inputColors, outputColors1, fragments1, group.get());
+
+ const char typesAndConstants2[] =
+ "%c_f32_p2 = OpConstant %f32 0.2\n";
+
+ // Add .4 to the second element of the given parameter.
+ const char function2[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%entry = OpLabel\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param\n"
+ "%loc = OpAccessChain %fp_f32 %result %c_i32_1\n"
+ "%val = OpLoad %f32 %loc\n"
+ " OpBranch %phi\n"
+
+ "%phi = OpLabel\n"
+ "%step = OpPhi %i32 %c_i32_0 %entry %step_next %phi\n"
+ "%accum = OpPhi %f32 %val %entry %accum_next %phi\n"
+ "%step_next = OpIAdd %i32 %step %c_i32_1\n"
+ "%accum_next = OpFAdd %f32 %accum %c_f32_p2\n"
+ "%still_loop = OpSLessThan %bool %step %c_i32_2\n"
+ " OpLoopMerge %exit %phi None\n"
+ " OpBranchConditional %still_loop %phi %exit\n"
+
+ "%exit = OpLabel\n"
+ " OpStore %loc %accum\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+
+ " OpFunctionEnd\n";
+
+ fragments2["pre_main"] = typesAndConstants2;
+ fragments2["testfun"] = function2;
+
+ outputColors2[0] = RGBA(127, 229, 127, 255);
+ outputColors2[1] = RGBA(127, 102, 0, 255);
+ outputColors2[2] = RGBA(0, 229, 0, 255);
+ outputColors2[3] = RGBA(0, 102, 127, 255);
+
+ createTestsForAllStages("induction", inputColors, outputColors2, fragments2, group.get());
+
+ const char typesAndConstants3[] =
+ "%true = OpConstantTrue %bool\n"
+ "%false = OpConstantFalse %bool\n"
+ "%c_f32_p2 = OpConstant %f32 0.2\n";
+
+ // Swap the second and the third element of the given parameter.
+ const char function3[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%entry = OpLabel\n"
+ "%result = OpVariable %fp_v4f32 Function\n"
+ " OpStore %result %param\n"
+ "%a_loc = OpAccessChain %fp_f32 %result %c_i32_1\n"
+ "%a_init = OpLoad %f32 %a_loc\n"
+ "%b_loc = OpAccessChain %fp_f32 %result %c_i32_2\n"
+ "%b_init = OpLoad %f32 %b_loc\n"
+ " OpBranch %phi\n"
+
+ "%phi = OpLabel\n"
+ "%still_loop = OpPhi %bool %true %entry %false %phi\n"
+ "%a_next = OpPhi %f32 %a_init %entry %b_next %phi\n"
+ "%b_next = OpPhi %f32 %b_init %entry %a_next %phi\n"
+ " OpLoopMerge %exit %phi None\n"
+ " OpBranchConditional %still_loop %phi %exit\n"
+
+ "%exit = OpLabel\n"
+ " OpStore %a_loc %a_next\n"
+ " OpStore %b_loc %b_next\n"
+ "%ret = OpLoad %v4f32 %result\n"
+ " OpReturnValue %ret\n"
+
+ " OpFunctionEnd\n";
+
+ fragments3["pre_main"] = typesAndConstants3;
+ fragments3["testfun"] = function3;
+
+ outputColors3[0] = RGBA(127, 127, 127, 255);
+ outputColors3[1] = RGBA(127, 0, 0, 255);
+ outputColors3[2] = RGBA(0, 0, 127, 255);
+ outputColors3[3] = RGBA(0, 127, 0, 255);
+
+ createTestsForAllStages("swap", inputColors, outputColors3, fragments3, group.get());
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createNoContractionTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
+ RGBA inputColors[4];
+ RGBA outputColors[4];
+
+ // With NoContraction, (1 + 2^-23) * (1 - 2^-23) - 1 should be conducted as a multiplication and an addition separately.
+ // For the multiplication, the result is 1 - 2^-46, which is out of the precision range for 32-bit float. (32-bit float
+ // only have 23-bit fraction.) So it will be rounded to 1. Then the final result is 0. On the contrary, the result will
+ // be 2^-46, which is a normalized number perfectly representable as 32-bit float.
+ const char constantsAndTypes[] =
+ "%c_vec4_0 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1\n"
+ "%c_vec4_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+ "%c_f32_1pl2_23 = OpConstant %f32 0x1.000002p+0\n" // 1 + 2^-23
+ "%c_f32_1mi2_23 = OpConstant %f32 0x1.fffffcp-1\n" // 1 - 2^-23
+ ;
+
+ const char function[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param = OpFunctionParameter %v4f32\n"
+ "%label = OpLabel\n"
+ "%var1 = OpVariable %fp_f32 Function %c_f32_1pl2_23\n"
+ "%var2 = OpVariable %fp_f32 Function\n"
+ "%red = OpCompositeExtract %f32 %param 0\n"
+ "%plus_red = OpFAdd %f32 %c_f32_1mi2_23 %red\n"
+ " OpStore %var2 %plus_red\n"
+ "%val1 = OpLoad %f32 %var1\n"
+ "%val2 = OpLoad %f32 %var2\n"
+ "%mul = OpFMul %f32 %val1 %val2\n"
+ "%add = OpFAdd %f32 %mul %c_f32_n1\n"
+ "%is0 = OpFOrdEqual %bool %add %c_f32_0\n"
+ "%ret = OpSelect %v4f32 %is0 %c_vec4_0 %c_vec4_1\n"
+ " OpReturnValue %ret\n"
+ " OpFunctionEnd\n";
+
+ struct CaseNameDecoration
+ {
+ string name;
+ string decoration;
+ };
+
+
+ CaseNameDecoration tests[] = {
+ {"multiplication", "OpDecorate %mul NoContraction"},
+ {"addition", "OpDecorate %add NoContraction"},
+ {"both", "OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"},
+ };
+
+ getHalfColorsFullAlpha(inputColors);
+
+ for (deUint8 idx = 0; idx < 4; ++idx)
+ {
+ inputColors[idx].setRed(0);
+ outputColors[idx] = RGBA(0, 0, 0, 255);
+ }
+
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(CaseNameDecoration); ++testNdx)
+ {
+ map<string, string> fragments;
+
+ fragments["decoration"] = tests[testNdx].decoration;
+ fragments["pre_main"] = constantsAndTypes;
+ fragments["testfun"] = function;
+
+ createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, group.get());
+ }
+
+ return group.release();
+}
+
+tcu::TestCaseGroup* createMemoryAccessTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> memoryAccessTests (new tcu::TestCaseGroup(testCtx, "opMemoryAccess", "Memory Semantics"));
+ RGBA colors[4];
+
+ const char constantsAndTypes[] =
+ "%c_a2f32_1 = OpConstantComposite %a2f32 %c_f32_1 %c_f32_1\n"
+ "%fp_a2f32 = OpTypePointer Function %a2f32\n"
+ "%stype = OpTypeStruct %v4f32 %a2f32 %f32\n"
+ "%fp_stype = OpTypePointer Function %stype\n";
+
+ const char function[] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%lbl = OpLabel\n"
+ "%v1 = OpVariable %fp_v4f32 Function\n"
+ " OpStore %v1 %c_v4f32_1_1_1_1\n"
+ "%v2 = OpVariable %fp_a2f32 Function\n"
+ " OpStore %v2 %c_a2f32_1\n"
+ "%v3 = OpVariable %fp_f32 Function\n"
+ " OpStore %v3 %c_f32_1\n"
+
+ "%v = OpVariable %fp_stype Function\n"
+
+ "%vv = OpVariable %fp_stype Function\n"
+ "%vvv = OpVariable %fp_f32 Function\n"
+
+ "%p_v4f32 = OpAccessChain %fp_v4_f32 %v %c_u32_0\n"
+ "%p_a2f32 = OpAccessChain %fp_a2f32 %v %c_u32_1\n"
+ "%p_f32 = OpAccessChain %fp_f32 %v %c_u32_2\n"
+ "%v1_v = OpLoad %v4f32 %v1 ${access_type}\n"
+ "%v2_v = OpLoad %a2f32 %v2 ${access_type}\n"
+ "%v3_v = OpLoad %f32 %v3 ${access_type}\n"
+
+ " OpStore %p_v4f32 %v1_v ${access_type}\n"
+ " OpStore %p_a2f32 %v2_v ${access_type}\n"
+ " OpStore %p_f32 %v3_v ${access_type}\n"
+
+ " OpCopyMemory %vv %v ${access_type}\n"
+ " OpCopyMemory %vvv %p_f32 ${access_type}\n"
+
+ "%p_f32_2 = OpAccessChain %fp_f32 %vv %c_u32_2\n"
+ "%v_f32_2 = OpLoad %f32 %p_f32_2\n"
+ "%v_f32_3 = OpLoad %f32 %vvv\n"
+
+ "%ret1 = OpVectorTimesScalar %v4f32 %param1 %v_f32_2\n"
+ "%ret2 = OpVectorTimesScalar %v4f32 %ret1 %v_f32_3\n"
+ " OpReturnValue %ret2\n"
+ " OpFunctionEnd\n";
+
+ struct NameMemoryAccess
+ {
+ string name;
+ string accessType;
+ };
+
+
+ NameMemoryAccess tests[] =
+ {
+ { "none", "" },
+ { "volatile", "Volatile" },
+ { "aligned", "Aligned 1" },
+ { "volatile-aligned", "Volatile|Aligned 1" },
+ { "nontemporal-aligned", "Nontemporal|Aligned 1" },
+ { "volatile-nontemporal", "Volatile|Nontemporal" },
+ { "volatile-nontermporal-aligned", "Volatile|NonTermporal|Aligned" },
+ };
+
+ getHalfColorsFullAlpha(colors);
+
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameMemoryAccess); ++testNdx)
+ {
+ map<string, string> fragments;
+ map<string, string> memoryAccess;
+ memoryAccess["access_type"] = tests[testNdx].accessType;
+
+ fragments["pre_main"] = constantsAndTypes;
+ fragments["testfun"] = tcu::StringTemplate(function).specialize(memoryAccess);
+ createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, memoryAccessTests.get());
+ }
+ return memoryAccessTests.release();
+}
+tcu::TestCaseGroup* createOpUndefTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> opUndefTests (new tcu::TestCaseGroup(testCtx, "opundef", "Test OpUndef"));
+ RGBA defaultColors[4];
+ map<string, string> fragments;
+ getDefaultColors(defaultColors);
+
+ // First, simple cases that don't do anything with the OpUndef result.
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %type\n"
+ "OpReturnValue %param1\n"
+ "OpFunctionEnd\n"
+ ;
+ struct NameCodePair { string name, code; };
+ const NameCodePair tests[] =
+ {
+ {"bool", "%type = OpTypeBool"},
+ {"vec2uint32", "%type = OpTypeVector %u32 2"},
+ {"image", "%type = OpTypeImage %f32 2D 0 0 0 0 Unknown"},
+ {"sampler", "%type = OpTypeSampler"},
+ {"sampledimage", "%img = OpTypeImage %f32 2D 0 0 0 0 Unknown\n" "%type = OpTypeSampledImage %img"},
+ {"function", "%type = OpTypeFunction %void %i32 %f32"},
+ {"pointer", "%type = OpTypePointer Function %i32"},
+ {"runtimearray", "%type = OpTypeRuntimeArray %f32"},
+ {"array", "%c_u32_100 = OpConstant %u32 100\n" "%type = OpTypeArray %i32 %c_u32_100"},
+ {"struct", "%type = OpTypeStruct %f32 %i32 %u32"}};
+ for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+ {
+ fragments["pre_main"] = tests[testNdx].code;
+ createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opUndefTests.get());
+ }
+ fragments.clear();
+
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %f32\n"
+ "%zero = OpFMul %f32 %undef %c_f32_0\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "%b = OpFAdd %f32 %a %zero\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %b %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("float32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %i32\n"
+ "%zero = OpIMul %i32 %undef %c_i32_0\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("sint32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %u32\n"
+ "%zero = OpIMul %u32 %undef %c_i32_0\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("uint32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %v4f32\n"
+ "%vzero = OpVectorTimesScalar %v4f32 %undef %c_f32_0\n"
+ "%zero_0 = OpVectorExtractDynamic %f32 %vzero %c_i32_0\n"
+ "%zero_1 = OpVectorExtractDynamic %f32 %vzero %c_i32_1\n"
+ "%zero_2 = OpVectorExtractDynamic %f32 %vzero %c_i32_2\n"
+ "%zero_3 = OpVectorExtractDynamic %f32 %vzero %c_i32_3\n"
+ "%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
+ "%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
+ "%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
+ "%sum_0 = OpFAdd %f32 %param1_0 %zero_0\n"
+ "%sum_1 = OpFAdd %f32 %param1_1 %zero_1\n"
+ "%sum_2 = OpFAdd %f32 %param1_2 %zero_2\n"
+ "%sum_3 = OpFAdd %f32 %param1_3 %zero_3\n"
+ "%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
+ "%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
+ "%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("vec4float32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+ fragments["pre_main"] =
+ "%v2f32 = OpTypeVector %f32 2\n"
+ "%m2x2f32 = OpTypeMatrix %v2f32 2\n";
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%undef = OpUndef %m2x2f32\n"
+ "%mzero = OpMatrixTimesScalar %m2x2f32 %undef %c_f32_0\n"
+ "%zero_0 = OpCompositeExtract %f32 %mzero 0 0\n"
+ "%zero_1 = OpCompositeExtract %f32 %mzero 0 1\n"
+ "%zero_2 = OpCompositeExtract %f32 %mzero 1 0\n"
+ "%zero_3 = OpCompositeExtract %f32 %mzero 1 1\n"
+ "%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
+ "%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
+ "%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
+ "%sum_0 = OpFAdd %f32 %param1_0 %zero_0\n"
+ "%sum_1 = OpFAdd %f32 %param1_1 %zero_1\n"
+ "%sum_2 = OpFAdd %f32 %param1_2 %zero_2\n"
+ "%sum_3 = OpFAdd %f32 %param1_3 %zero_3\n"
+ "%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
+ "%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
+ "%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("matrix", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+ return opUndefTests.release();
+}
+
+void createOpQuantizeSingleOptionTests(tcu::TestCaseGroup* testCtx)
+{
+ const RGBA inputColors[4] =
+ {
+ RGBA(0, 0, 0, 255),
+ RGBA(0, 0, 255, 255),
+ RGBA(0, 255, 0, 255),
+ RGBA(0, 255, 255, 255)
+ };
+
+ const RGBA expectedColors[4] =
+ {
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255)
+ };
+
+ const struct SingleFP16Possibility
+ {
+ const char* name;
+ const char* constant;
+ float valueAsFloat;
+ const char* condition;
+ // condition must evaluate to true after %test_constant = OpQuantizeToF16(%constant)
+ } tests[] =
+ {
+ {
+ "negative",
+ "-0x1.3p1\n",
+ -constructNormalizedFloat(1, 0x300000),
+ "%cond = OpFOrdEqual %bool %c %test_constant\n"
+ }, // -19
+ {
+ "positive",
+ "0x1.0p7\n",
+ constructNormalizedFloat(7, 0x000000),
+ "%cond = OpFOrdEqual %bool %c %test_constant\n"
+ }, // +128
+ // SPIR-V requires that OpQuantizeToF16 flushes
+ // any numbers that would end up denormalized in F16 to zero.
+ {
+ "denorm",
+ "0x0.0006p-126\n",
+ std::ldexp(1.5f, -140),
+ "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+ }, // denorm
+ {
+ "negative_denorm",
+ "-0x0.0006p-126\n",
+ -std::ldexp(1.5f, -140),
+ "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+ }, // -denorm
+ {
+ "too_small",
+ "0x1.0p-16\n",
+ std::ldexp(1.0f, -16),
+ "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+ }, // too small negative
+ {
+ "negative_too_small",
+ "-0x1.0p-32\n",
+ -std::ldexp(1.0f, -32),
+ "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+ }, // too small positive
+ {
+ "negative_inf",
+ "-0x1.0p128\n",
+ -std::ldexp(1.0f, 128),
+ "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+
+ "%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
+ "%inf = OpIsInf %bool %c\n"
+ "%cond = OpLogicalAnd %bool %gz %inf\n"
+ }, // -inf to -inf
+ {
+ "inf",
+ "0x1.0p128\n",
+ std::ldexp(1.0f, 128),
+
+ "%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
+ "%inf = OpIsInf %bool %c\n"
+ "%cond = OpLogicalAnd %bool %gz %inf\n"
+ }, // +inf to +inf
+ {
+ "round_to_negative_inf",
+ "-0x1.0p32\n",
+ -std::ldexp(1.0f, 32),
+
+ "%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
+ "%inf = OpIsInf %bool %c\n"
+ "%comp = OpLogicalAnd %bool %gz %inf\n"
+ }, // round to -inf
+ {
+ "round_to_inf",
+ "0x1.0p16\n",
+ std::ldexp(1.0f, 16),
+
+ "%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
+ "%inf = OpIsInf %bool %c\n"
+ "%cond = OpLogicalAnd %bool %gz %inf\n"
+ }, // round to +inf
+ {
+ "nan",
+ "0x1.1p128\n",
+ std::numeric_limits<float>::quiet_NaN(),
+
+ "%nan = OpIsNan %bool %c\n"
+ "%as_int = OpBitcast %i32 %c\n"
+ "%positive = OpSGreaterThan %bool %as_int %c_i32_0\n"
+ "%cond = OpLogicalAnd %bool %nan %positive\n"
+ }, // nan
+ {
+ "negative_nan",
+ "-0x1.0001p128\n",
+ std::numeric_limits<float>::quiet_NaN(),
+
+ "%nan = OpIsNan %bool %c\n"
+ "%as_int = OpBitcast %i32 %c\n"
+ "%negative = OpSLessThan %bool %as_int %c_i32_0\n"
+ "%cond = OpLogicalAnd %bool %nan %negative\n"
+ } // -nan
+ };
+ const char* constants =
+ "%test_constant = OpConstant %f32\n";
+
+ StringTemplate function (
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "%b = OpFAdd %f32 %test_constant %a\n"
+ "%c = OpQuantizeToF16 %f32 %b\n"
+ "${condition}\n"
+ "%retval = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+ " OpReturnValue %retval\n"
+ );
+
+ const char* specDecorations = "OpDecorate %test_constant SpecId 0\n";
+ const char* specConstants =
+ "%test_constant = OpSpecConstant %f32 0.\n"
+ "%c = OpSpecConstantOp %f32 QuantizeToF16 %test_constant\n";
+
+ StringTemplate specConstantFunction(
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "${condition}\n"
+ "%retval = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+ " OpReturnValue %retval\n"
+ );
+
+ for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
+ {
+ map<string, string> codeSpecialization;
+ map<string, string> fragments;
+ codeSpecialization["condition"] = tests[idx].condition;
+ fragments["testfun"] = function.specialize(codeSpecialization);
+ fragments["pre_main"] = string(constants) + tests[idx].constant + "\n";
+ createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
+ }
+
+ for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
+ {
+ map<string, string> codeSpecialization;
+ map<string, string> fragments;
+ vector<deInt32> passConstants;
+ deInt32 specConstant;
+
+ codeSpecialization["condition"] = tests[idx].condition;
+ fragments["testfun"] = specConstantFunction.specialize(codeSpecialization);
+ fragments["decoration"] = specDecorations;
+ fragments["pre_main"] = specConstants;
+
+ memcpy(&specConstant, &tests[idx].valueAsFloat, sizeof(float));
+ passConstants.push_back(specConstant);
+
+ createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
+ }
+}
+
+void createOpQuantizeTwoPossibilityTests(tcu::TestCaseGroup* testCtx)
+{
+ RGBA inputColors[4] = {
+ RGBA(0, 0, 0, 255),
+ RGBA(0, 0, 255, 255),
+ RGBA(0, 255, 0, 255),
+ RGBA(0, 255, 255, 255)
+ };
+
+ RGBA expectedColors[4] =
+ {
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255),
+ RGBA(255, 0, 0, 255)
+ };
+
+ struct DualFP16Possibility
+ {
+ const char* name;
+ const char* input;
+ float inputAsFloat;
+ const char* possibleOutput1;
+ const char* possibleOutput2;
+ } tests[] = {
+ {
+ "positive_round_up_or_round_down",
+ "0x1.3003p8",
+ constructNormalizedFloat(8, 0x300300),
+ "0x1.304p8",
+ "0x1.3p8"
+ },
+ {
+ "negative_round_up_or_round_down",
+ "-0x1.6008p-7",
+ -constructNormalizedFloat(8, 0x600800),
+ "-0x1.6p-7",
+ "-0x1.604p-7"
+ },
+ {
+ "carry_bit",
+ "0x1.01ep2",
+ constructNormalizedFloat(8, 0x01e000),
+ "0x1.01cp2",
+ "0x1.02p2"
+ },
+ {
+ "carry_to_exponent",
+ "0x1.feep1",
+ constructNormalizedFloat(8, 0xfee000),
+ "0x1.ffcp1",
+ "0x1.0p2"
+ },
+ };
+ StringTemplate constants (
+ "%input_const = OpConstant %f32 ${input}\n"
+ "%possible_solution1 = OpConstant %f32 ${output1}\n"
+ "%possible_solution2 = OpConstant %f32 ${output2}\n"
+ );
+
+ StringTemplate specConstants (
+ "%input_const = OpSpecConstant %f32 0.\n"
+ "%possible_solution1 = OpConstant %f32 ${output1}\n"
+ "%possible_solution2 = OpConstant %f32 ${output2}\n"
+ );
+
+ const char* specDecorations = "OpDecorate %input_const SpecId 0\n";
+
+ const char* function =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ // For the purposes of this test we assume that 0.f will always get
+ // faithfully passed through the pipeline stages.
+ "%b = OpFAdd %f32 %test_constant %a\n"
+ "%c = OpQuantizeToF16 %f32 %b\n"
+ "%eq_1 = OpFOrdEqual %bool %c %possible_solution1\n"
+ "%eq_2 = OpFOrdEqual %bool %c %possible_solution2\n"
+ "%cond = OpLogicalOr %bool %eq_1 %eq_2\n"
+ "%retval = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+ " OpReturnValue %retval\n";
+
+ for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
+ map<string, string> fragments;
+ map<string, string> constantSpecialization;
+
+ constantSpecialization["input"] = tests[idx].input;
+ constantSpecialization["output1"] = tests[idx].possibleOutput1;
+ constantSpecialization["output2"] = tests[idx].possibleOutput2;
+ fragments["testfun"] = function;
+ fragments["pre_main"] = constants.specialize(constantSpecialization);
+ createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
+ }
+
+ for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
+ map<string, string> fragments;
+ map<string, string> constantSpecialization;
+ vector<deInt32> passConstants;
+ deInt32 specConstant;
+
+ constantSpecialization["output1"] = tests[idx].possibleOutput1;
+ constantSpecialization["output2"] = tests[idx].possibleOutput2;
+ fragments["testfun"] = function;
+ fragments["decoration"] = specDecorations;
+ fragments["pre_main"] = specConstants.specialize(constantSpecialization);
+
+ memcpy(&specConstant, &tests[idx].inputAsFloat, sizeof(float));
+ passConstants.push_back(specConstant);
+
+ createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
+ }
+}
+
+tcu::TestCaseGroup* createOpQuantizeTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> opQuantizeTests (new tcu::TestCaseGroup(testCtx, "opquantize", "Test OpQuantizeToF16"));
+ createOpQuantizeSingleOptionTests(opQuantizeTests.get());
+ createOpQuantizeTwoPossibilityTests(opQuantizeTests.get());
+ return opQuantizeTests.release();
+}
+
+struct ShaderPermutation
+{
+ deUint8 vertexPermutation;
+ deUint8 geometryPermutation;
+ deUint8 tesscPermutation;
+ deUint8 tessePermutation;
+ deUint8 fragmentPermutation;
+};
+
+ShaderPermutation getShaderPermutation(deUint8 inputValue)
+{
+ ShaderPermutation permutation =
+ {
+ static_cast<deUint8>(inputValue & 0x10? 1u: 0u),
+ static_cast<deUint8>(inputValue & 0x08? 1u: 0u),
+ static_cast<deUint8>(inputValue & 0x04? 1u: 0u),
+ static_cast<deUint8>(inputValue & 0x02? 1u: 0u),
+ static_cast<deUint8>(inputValue & 0x01? 1u: 0u)
+ };
+ return permutation;
+}
+
+tcu::TestCaseGroup* createModuleTests(tcu::TestContext& testCtx)
+{
+ RGBA defaultColors[4];
+ RGBA invertedColors[4];
+ de::MovePtr<tcu::TestCaseGroup> moduleTests (new tcu::TestCaseGroup(testCtx, "module", "Multiple entry points into shaders"));
+
+ const ShaderElement combinedPipeline[] =
+ {
+ ShaderElement("module", "main", VK_SHADER_STAGE_VERTEX_BIT),
+ ShaderElement("module", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
+ ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+ ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+ ShaderElement("module", "main", VK_SHADER_STAGE_FRAGMENT_BIT)
+ };
+
+ getDefaultColors(defaultColors);
+ getInvertedDefaultColors(invertedColors);
+ addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), "same-module", "", createCombinedModule, runAndVerifyDefaultPipeline, createInstanceContext(combinedPipeline, map<string, string>()));
+
+ const char* numbers[] =
+ {
+ "1", "2"
+ };
+
+ for (deInt8 idx = 0; idx < 32; ++idx)
+ {
+ ShaderPermutation permutation = getShaderPermutation(idx);
+ string name = string("vert") + numbers[permutation.vertexPermutation] + "-geom" + numbers[permutation.geometryPermutation] + "-tessc" + numbers[permutation.tesscPermutation] + "-tesse" + numbers[permutation.tessePermutation] + "-frag" + numbers[permutation.fragmentPermutation];
+ const ShaderElement pipeline[] =
+ {
+ ShaderElement("vert", string("vert") + numbers[permutation.vertexPermutation], VK_SHADER_STAGE_VERTEX_BIT),
+ ShaderElement("geom", string("geom") + numbers[permutation.geometryPermutation], VK_SHADER_STAGE_GEOMETRY_BIT),
+ ShaderElement("tessc", string("tessc") + numbers[permutation.tesscPermutation], VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+ ShaderElement("tesse", string("tesse") + numbers[permutation.tessePermutation], VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+ ShaderElement("frag", string("frag") + numbers[permutation.fragmentPermutation], VK_SHADER_STAGE_FRAGMENT_BIT)
+ };
+
+ // If there are an even number of swaps, then it should be no-op.
+ // If there are an odd number, the color should be flipped.
+ if ((permutation.vertexPermutation + permutation.geometryPermutation + permutation.tesscPermutation + permutation.tessePermutation + permutation.fragmentPermutation) % 2 == 0)
+ {
+ addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, defaultColors, map<string, string>()));
+ }
+ else
+ {
+ addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, invertedColors, map<string, string>()));
+ }
+ }
+ return moduleTests.release();
+}
+
+tcu::TestCaseGroup* createLoopTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "loop", "Looping control flow"));
+ RGBA defaultColors[4];
+ getDefaultColors(defaultColors);
+ map<string, string> fragments;
+
+ // A loop with a single block. The Continue Target is the loop block
+ // itself. In SPIR-V terms, the "loop construct" contains no blocks at all
+ // -- the "continue construct" forms the entire loop.
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+
+ "%entry = OpLabel\n"
+ "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "OpBranch %loop\n"
+
+ ";adds and subtracts 1.0 to %val in alternate iterations\n"
+ "%loop = OpLabel\n"
+ "%count = OpPhi %i32 %c_i32_4 %entry %count__ %loop\n"
+ "%delta = OpPhi %f32 %c_f32_1 %entry %minus_delta %loop\n"
+ "%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
+ "%val = OpFAdd %f32 %val1 %delta\n"
+ "%minus_delta = OpFSub %f32 %c_f32_0 %delta\n"
+ "%count__ = OpISub %i32 %count %c_i32_1\n"
+ "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+ "OpLoopMerge %exit %loop None\n"
+ "OpBranchConditional %again %loop %exit\n"
+
+ "%exit = OpLabel\n"
+ "%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
+ "OpReturnValue %result\n"
+
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("single-block", defaultColors, defaultColors, fragments, testGroup.get());
+
+ fragments["pre_main"] = "%c_f32_neg1 = OpConstant %f32 -1.0\n";
+
+ // Body comprised of multiple basic blocks.
+ const StringTemplate multiBlock(
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+
+ "%entry = OpLabel\n"
+ "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "OpBranch %loop\n"
+
+ ";adds and subtracts 1.0 to %val in alternate iterations\n"
+ "%loop = OpLabel\n"
+ "%count = OpPhi %i32 %c_i32_4 %entry %count__ %gather\n"
+ "%delta = OpPhi %f32 %c_f32_1 %entry %delta_next %gather\n"
+ "%val1 = OpPhi %f32 %val0 %entry %val %gather\n"
+ // There are several possibilities for the Continue Target below. Each
+ // will be specialized into a separate test case.
+ "OpLoopMerge %exit ${continue_target} None\n"
+ "OpBranch %if\n"
+
+ "%if = OpLabel\n"
+ ";delta_next = (delta > 0) ? -1 : 1;\n"
+ "%gt0 = OpFOrdGreaterThan %bool %delta %c_f32_0\n"
+ "OpSelectionMerge %gather DontFlatten\n"
+ "OpBranchConditional %gt0 %even %odd ;tells us if %count is even or odd\n"
+
+ "%odd = OpLabel\n"
+ "OpBranch %gather\n"
+
+ "%even = OpLabel\n"
+ "OpBranch %gather\n"
+
+ "%gather = OpLabel\n"
+ "%delta_next = OpPhi %f32 %c_f32_neg1 %even %c_f32_1 %odd\n"
+ "%val = OpFAdd %f32 %val1 %delta\n"
+ "%count__ = OpISub %i32 %count %c_i32_1\n"
+ "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+ "OpBranchConditional %again %loop %exit\n"
+
+ "%exit = OpLabel\n"
+ "%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
+ "OpReturnValue %result\n"
+
+ "OpFunctionEnd\n");
+
+ map<string, string> continue_target;
+
+ // The Continue Target is the loop block itself.
+ continue_target["continue_target"] = "%loop";
+ fragments["testfun"] = multiBlock.specialize(continue_target);
+ createTestsForAllStages("multi-block-continue-construct", defaultColors, defaultColors, fragments, testGroup.get());
+
+ // The Continue Target is at the end of the loop.
+ continue_target["continue_target"] = "%gather";
+ fragments["testfun"] = multiBlock.specialize(continue_target);
+ createTestsForAllStages("multi-block-loop-construct", defaultColors, defaultColors, fragments, testGroup.get());
+
+ // \todo [2015-12-14 dekimir] More cases:
+ // - continue
+ // - early exit
+
+ return testGroup.release();
+}
+
+// Adds a new test to group using custom fragments for the tessellation-control
+// stage and passthrough fragments for all other stages. Uses default colors
+// for input and expected output.
+void addTessCtrlTest(tcu::TestCaseGroup* group, const char* name, const map<string, string>& fragments)
+{
+ RGBA defaultColors[4];
+ getDefaultColors(defaultColors);
+ const ShaderElement pipelineStages[] =
+ {
+ ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
+ ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+ ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+ ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
+ ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
+ };
+
+ addFunctionCaseWithPrograms<InstanceContext>(group, name, "", addShaderCodeCustomTessControl,
+ runAndVerifyDefaultPipeline, createInstanceContext(
+ pipelineStages, defaultColors, defaultColors, fragments, StageToSpecConstantMap()));
+}
+
+// A collection of tests putting OpControlBarrier in places GLSL forbids but SPIR-V allows.
+tcu::TestCaseGroup* createBarrierTests(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "barrier", "OpControlBarrier"));
+ map<string, string> fragments;
+
+ // A barrier inside a function body.
+ fragments["pre_main"] =
+ "%Workgroup = OpConstant %i32 2\n"
+ "%SequentiallyConsistent = OpConstant %i32 0x10\n";
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "OpReturnValue %param1\n"
+ "OpFunctionEnd\n";
+ addTessCtrlTest(testGroup.get(), "in-function", fragments);
+
+ // Common setup code for the following tests.
+ fragments["pre_main"] =
+ "%Workgroup = OpConstant %i32 2\n"
+ "%SequentiallyConsistent = OpConstant %i32 0x10\n"
+ "%c_f32_5 = OpConstant %f32 5.\n";
+ const string setupPercentZero = // Begins %test_code function with code that sets %zero to 0u but cannot be optimized away.
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%entry = OpLabel\n"
+ ";param1 components are between 0 and 1, so dot product is 4 or less\n"
+ "%dot = OpDot %f32 %param1 %param1\n"
+ "%div = OpFDiv %f32 %dot %c_f32_5\n"
+ "%zero = OpConvertFToU %u32 %div\n";
+
+ // Barriers inside OpSwitch branches.
+ fragments["testfun"] =
+ setupPercentZero +
+ "OpSelectionMerge %switch_exit None\n"
+ "OpSwitch %zero %switch_default 0 %case0 1 %case1 ;should always go to %case0\n"
+
+ "%case1 = OpLabel\n"
+ ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "%wrong_branch_alert1 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+ "OpBranch %switch_exit\n"
+
+ "%switch_default = OpLabel\n"
+ "%wrong_branch_alert2 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+ ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "OpBranch %switch_exit\n"
+
+ "%case0 = OpLabel\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "OpBranch %switch_exit\n"
+
+ "%switch_exit = OpLabel\n"
+ "%ret = OpPhi %v4f32 %param1 %case0 %wrong_branch_alert1 %case1 %wrong_branch_alert2 %switch_default\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n";
+ addTessCtrlTest(testGroup.get(), "in-switch", fragments);
+
+ // Barriers inside if-then-else.
+ fragments["testfun"] =
+ setupPercentZero +
+ "%eq0 = OpIEqual %bool %zero %c_u32_0\n"
+ "OpSelectionMerge %exit DontFlatten\n"
+ "OpBranchConditional %eq0 %then %else\n"
+
+ "%else = OpLabel\n"
+ ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "%wrong_branch_alert = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+ "OpBranch %exit\n"
+
+ "%then = OpLabel\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "OpBranch %exit\n"
+
+ "%exit = OpLabel\n"
+ "%ret = OpPhi %v4f32 %param1 %then %wrong_branch_alert %else\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n";
+ addTessCtrlTest(testGroup.get(), "in-if", fragments);
+
+ // A barrier after control-flow reconvergence, tempting the compiler to attempt something like this:
+ // http://lists.llvm.org/pipermail/llvm-dev/2009-October/026317.html.
+ fragments["testfun"] =
+ setupPercentZero +
+ "%thread_id = OpLoad %i32 %gl_InvocationID\n"
+ "%thread0 = OpIEqual %bool %thread_id %c_i32_0\n"
+ "OpSelectionMerge %exit DontFlatten\n"
+ "OpBranchConditional %thread0 %then %else\n"
+
+ "%else = OpLabel\n"
+ "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "OpBranch %exit\n"
+
+ "%then = OpLabel\n"
+ "%val1 = OpVectorExtractDynamic %f32 %param1 %zero\n"
+ "OpBranch %exit\n"
+
+ "%exit = OpLabel\n"
+ "%val = OpPhi %f32 %val0 %else %val1 %then\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %val %zero\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n";
+ addTessCtrlTest(testGroup.get(), "after-divergent-if", fragments);
+
+ // A barrier inside a loop.
+ fragments["pre_main"] =
+ "%Workgroup = OpConstant %i32 2\n"
+ "%SequentiallyConsistent = OpConstant %i32 0x10\n"
+ "%c_f32_10 = OpConstant %f32 10.\n";
+ fragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%entry = OpLabel\n"
+ "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "OpBranch %loop\n"
+
+ ";adds 1, 2, 3, and 4 to %val0\n"
+ "%loop = OpLabel\n"
+ "%count = OpPhi %i32 %c_i32_4 %entry %count__ %latch\n"
+ "%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
+ "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+ "%fcount = OpConvertSToF %f32 %count\n"
+ "%val = OpFAdd %f32 %val1 %fcount\n"
+ "%count__ = OpISub %i32 %count %c_i32_1\n"
+ "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+ "OpLoopMerge %exit %loop None\n"
+ "OpBranchConditional %again %loop %exit\n"
+
+ "%exit = OpLabel\n"
+ "%same = OpFSub %f32 %val %c_f32_10\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %same %c_i32_0\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n";
+ addTessCtrlTest(testGroup.get(), "in-loop", fragments);
+
+ return testGroup.release();
+}
+
+tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> instructionTests (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
+ de::MovePtr<tcu::TestCaseGroup> computeTests (new tcu::TestCaseGroup(testCtx, "compute", "Compute Instructions with special opcodes/operands"));
+ de::MovePtr<tcu::TestCaseGroup> graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics", "Graphics Instructions with special opcodes/operands"));
+
+ computeTests->addChild(createOpNopGroup(testCtx));
+ computeTests->addChild(createOpLineGroup(testCtx));
+ computeTests->addChild(createOpNoLineGroup(testCtx));
+ computeTests->addChild(createOpConstantNullGroup(testCtx));
+ computeTests->addChild(createOpConstantCompositeGroup(testCtx));
+ computeTests->addChild(createOpConstantUsageGroup(testCtx));
+ computeTests->addChild(createSpecConstantGroup(testCtx));
+ computeTests->addChild(createOpSourceGroup(testCtx));
+ computeTests->addChild(createOpSourceExtensionGroup(testCtx));
+ computeTests->addChild(createDecorationGroupGroup(testCtx));
+ computeTests->addChild(createOpPhiGroup(testCtx));
+ computeTests->addChild(createLoopControlGroup(testCtx));
+ computeTests->addChild(createFunctionControlGroup(testCtx));
+ computeTests->addChild(createSelectionControlGroup(testCtx));
+ computeTests->addChild(createBlockOrderGroup(testCtx));
+ computeTests->addChild(createMultipleShaderGroup(testCtx));
+ computeTests->addChild(createMemoryAccessGroup(testCtx));
+ computeTests->addChild(createOpCopyMemoryGroup(testCtx));
+ computeTests->addChild(createOpCopyObjectGroup(testCtx));
+ computeTests->addChild(createNoContractionGroup(testCtx));
+ computeTests->addChild(createOpUndefGroup(testCtx));
+ computeTests->addChild(createOpUnreachableGroup(testCtx));
+ computeTests ->addChild(createOpQuantizeToF16Group(testCtx));
+
+ RGBA defaultColors[4];
+ getDefaultColors(defaultColors);
+
+ de::MovePtr<tcu::TestCaseGroup> opnopTests (new tcu::TestCaseGroup(testCtx, "opnop", "Test OpNop"));
+ map<string, string> opNopFragments;
+ opNopFragments["testfun"] =
+ "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+ "%param1 = OpFunctionParameter %v4f32\n"
+ "%label_testfun = OpLabel\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpNop\n"
+ "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+ "%b = OpFAdd %f32 %a %a\n"
+ "OpNop\n"
+ "%c = OpFSub %f32 %b %a\n"
+ "%ret = OpVectorInsertDynamic %v4f32 %param1 %c %c_i32_0\n"
+ "OpNop\n"
+ "OpNop\n"
+ "OpReturnValue %ret\n"
+ "OpFunctionEnd\n"
+ ;
+ createTestsForAllStages("opnop", defaultColors, defaultColors, opNopFragments, opnopTests.get());
+
+
+ graphicsTests->addChild(opnopTests.release());
+ graphicsTests->addChild(createOpSourceTests(testCtx));
+ graphicsTests->addChild(createOpSourceContinuedTests(testCtx));
+ graphicsTests->addChild(createOpLineTests(testCtx));
+ graphicsTests->addChild(createOpNoLineTests(testCtx));
+ graphicsTests->addChild(createOpConstantNullTests(testCtx));
+ graphicsTests->addChild(createOpConstantCompositeTests(testCtx));
+ graphicsTests->addChild(createMemoryAccessTests(testCtx));
+ graphicsTests->addChild(createOpUndefTests(testCtx));
+ graphicsTests->addChild(createSelectionBlockOrderTests(testCtx));
+ graphicsTests->addChild(createModuleTests(testCtx));
+ graphicsTests->addChild(createSwitchBlockOrderTests(testCtx));
+ graphicsTests->addChild(createOpPhiTests(testCtx));
+ graphicsTests->addChild(createNoContractionTests(testCtx));
+ graphicsTests->addChild(createOpQuantizeTests(testCtx));
+ graphicsTests->addChild(createLoopTests(testCtx));
+ graphicsTests->addChild(createSpecConstantTests(testCtx));
+ graphicsTests->addChild(createSpecConstantOpQuantizeToF16Group(testCtx));
+ graphicsTests->addChild(createBarrierTests(testCtx));
+ graphicsTests->addChild(createDecorationGroupTests(testCtx));
+
+ instructionTests->addChild(computeTests.release());
+ instructionTests->addChild(graphicsTests.release());
+
return instructionTests.release();
}
+++ /dev/null
-/*-------------------------------------------------------------------------
- * Vulkan Conformance Tests
- * ------------------------
- *
- * Copyright (c) 2015 Google Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and/or associated documentation files (the
- * "Materials"), to deal in the Materials without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Materials, and to
- * permit persons to whom the Materials are furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice(s) and this permission notice shall be
- * included in all copies or substantial portions of the Materials.
- *
- * The Materials are Confidential Information as defined by the
- * Khronos Membership Agreement until designated non-confidential by
- * Khronos, at which point this condition clause shall be removed.
- *
- * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
- *
- *//*!
- * \file
- * \brief Platform information tests
- *//*--------------------------------------------------------------------*/
-
-#include "vktInfo.hpp"
-
-#include "vktTestCaseUtil.hpp"
-
-#include "vkPlatform.hpp"
-#include "vkStrUtil.hpp"
-#include "vkRef.hpp"
-#include "vkDeviceUtil.hpp"
-#include "vkQueryUtil.hpp"
-
-#include "tcuTestLog.hpp"
-#include "tcuFormatUtil.hpp"
-
-#include "deUniquePtr.hpp"
-#include "deMemory.h"
-
-namespace vkt
-{
-namespace
-{
-
-using namespace vk;
-using std::vector;
-using std::string;
-using tcu::TestLog;
-using tcu::ScopedLogSection;
-
-tcu::TestStatus enumeratePhysicalDevices (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- const vector<VkPhysicalDevice> devices = enumeratePhysicalDevices(context.getInstanceInterface(), context.getInstance());
-
- log << TestLog::Integer("NumDevices", "Number of devices", "", QP_KEY_TAG_NONE, deInt64(devices.size()));
-
- for (size_t ndx = 0; ndx < devices.size(); ndx++)
- log << TestLog::Message << ndx << ": " << devices[ndx] << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Enumerating devices succeeded");
-}
-
-tcu::TestStatus enumerateInstanceLayers (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- const vector<VkLayerProperties> properties = enumerateInstanceLayerProperties(context.getPlatformInterface());
-
- for (size_t ndx = 0; ndx < properties.size(); ndx++)
- log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Enumerating layers succeeded");
-}
-
-tcu::TestStatus enumerateInstanceExtensions (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
-
- {
- const ScopedLogSection section (log, "Global", "Global Extensions");
- const vector<VkExtensionProperties> properties = enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL);
-
- for (size_t ndx = 0; ndx < properties.size(); ndx++)
- log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
- }
-
- {
- const vector<VkLayerProperties> layers = enumerateInstanceLayerProperties(context.getPlatformInterface());
-
- for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
- {
- const ScopedLogSection section (log, layer->layerName, string("Layer: ") + layer->layerName);
- const vector<VkExtensionProperties> properties = enumerateInstanceExtensionProperties(context.getPlatformInterface(), layer->layerName);
-
- for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
- log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
- }
- }
-
- return tcu::TestStatus::pass("Enumerating extensions succeeded");
-}
-
-tcu::TestStatus enumerateDeviceLayers (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- const vector<VkLayerProperties> properties = vk::enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
- for (size_t ndx = 0; ndx < properties.size(); ndx++)
- log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Enumerating layers succeeded");
-}
-
-tcu::TestStatus enumerateDeviceExtensions (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
-
- {
- const ScopedLogSection section (log, "Global", "Global Extensions");
- const vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), DE_NULL);
-
- for (size_t ndx = 0; ndx < properties.size(); ndx++)
- log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
- }
-
- {
- const vector<VkLayerProperties> layers = enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
- for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
- {
- const ScopedLogSection section (log, layer->layerName, string("Layer: ") + layer->layerName);
- const vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), layer->layerName);
-
- for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
- log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
- }
- }
-
- return tcu::TestStatus::pass("Enumerating extensions succeeded");
-}
-
-tcu::TestStatus deviceFeatures (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- VkPhysicalDeviceFeatures features;
-
- deMemset(&features, 0, sizeof(features));
-
- context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
-
- log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
- << TestLog::Message << features << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Query succeeded");
-}
-
-tcu::TestStatus deviceProperties (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- VkPhysicalDeviceProperties props;
-
- deMemset(&props, 0, sizeof(props));
-
- context.getInstanceInterface().getPhysicalDeviceProperties(context.getPhysicalDevice(), &props);
-
- log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
- << TestLog::Message << props << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Query succeeded");
-}
-
-tcu::TestStatus deviceQueueFamilyProperties (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
- const vector<VkQueueFamilyProperties> queueProperties = getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
- log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
-
- for (size_t queueNdx = 0; queueNdx < queueProperties.size(); queueNdx++)
- log << TestLog::Message << queueNdx << ": " << queueProperties[queueNdx] << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Querying queue properties succeeded");
-}
-
-tcu::TestStatus deviceMemoryProperties (Context& context)
-{
- TestLog& log = context.getTestContext().getLog();
-
- log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
-
- log << TestLog::Message
- << getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())
- << TestLog::EndMessage;
-
- return tcu::TestStatus::pass("Querying memory properties succeeded");
-}
-
-} // anonymous
-
-tcu::TestCaseGroup* createInfoTests (tcu::TestContext& testCtx)
-{
- de::MovePtr<tcu::TestCaseGroup> infoTests (new tcu::TestCaseGroup(testCtx, "info", "Platform Information Tests"));
-
- {
- de::MovePtr<tcu::TestCaseGroup> instanceInfoTests (new tcu::TestCaseGroup(testCtx, "instance", "Instance Information Tests"));
-
- addFunctionCase(instanceInfoTests.get(), "physical_devices", "Physical devices", enumeratePhysicalDevices);
- addFunctionCase(instanceInfoTests.get(), "layers", "Layers", enumerateInstanceLayers);
- addFunctionCase(instanceInfoTests.get(), "extensions", "Extensions", enumerateInstanceExtensions);
-
- infoTests->addChild(instanceInfoTests.release());
- }
-
- {
- de::MovePtr<tcu::TestCaseGroup> deviceInfoTests (new tcu::TestCaseGroup(testCtx, "device", "Device Information Tests"));
-
- addFunctionCase(deviceInfoTests.get(), "features", "Device Features", deviceFeatures);
- addFunctionCase(deviceInfoTests.get(), "properties", "Device Properties", deviceProperties);
- addFunctionCase(deviceInfoTests.get(), "queue_family_properties", "Queue family properties", deviceQueueFamilyProperties);
- addFunctionCase(deviceInfoTests.get(), "memory_properties", "Memory properties", deviceMemoryProperties);
- addFunctionCase(deviceInfoTests.get(), "layers", "Layers", enumerateDeviceLayers);
- addFunctionCase(deviceInfoTests.get(), "extensions", "Extensions", enumerateDeviceExtensions);
-
- infoTests->addChild(deviceInfoTests.release());
- }
-
- return infoTests.release();
-}
-
-} // vkt
if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
{
- const tcu::TextureFormat depthFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
- const tcu::TextureFormat stencilFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+ const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachmentInfo.getFormat());
+ const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachmentInfo.getFormat());
m_bufferSize = size.x() * size.y() * depthFormat.getPixelSize();
m_secondaryBufferSize = size.x() * size.y() * stencilFormat.getPixelSize();
VK_COMPARE_OP_ALWAYS, // stencilCompareOp
~0u, // stencilCompareMask
~0u, // stencilWriteMask
- ~0u // stencilReference
+ STENCIL_VALUE // stencilReference
}, // front
{
VK_STENCIL_OP_REPLACE, // stencilFailOp
VK_COMPARE_OP_ALWAYS, // stencilCompareOp
~0u, // stencilCompareMask
~0u, // stencilWriteMask
- ~0u // stencilReference
+ STENCIL_VALUE // stencilReference
}, // back
-1.0f, // minDepthBounds;
};
const VkImageSubresourceRange range =
{
- (VkImageAspectFlags)(hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0
- | hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0),
+ (VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
+ | (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
0,
1,
0,
de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
const BVec4 channelMask = tcu::getTextureFormatChannelMask(format);
+ IVec4 formatBitDepths = tcu::getTextureFormatBitDepth(format);
+ Vec4 threshold = Vec4(1.0f) / Vec4((float)(1 << formatBitDepths.x()),
+ (float)(1 << formatBitDepths.y()),
+ (float)(1 << formatBitDepths.z()),
+ (float)(1 << formatBitDepths.w()));
+
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
const Vec4 resColor (result.getPixel(x, y));
const Vec4 minRefColor = srgb ? tcu::linearToSRGB(valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs))
- : valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
+ : valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs) - threshold;
const Vec4 maxRefColor = srgb ? tcu::linearToSRGB(valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs))
- : valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
+ : valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs) + threshold;
DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
{
- const tcu::TextureFormat depthFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
+ const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachment.getFormat());
const VkDeviceSize depthBufferSize = targetSize.x() * targetSize.y() * depthFormat.getPixelSize();
void* const depthPtr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
- const tcu::TextureFormat stencilFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+ const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachment.getFormat());
const VkDeviceSize stencilBufferSize = targetSize.x() * targetSize.y() * stencilFormat.getPixelSize();
- void* const stencilPtr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
+ void* const stencilPtr = attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr();
const VkMappedMemoryRange ranges[] =
{
#include "deUniquePtr.hpp"
-#include "vktInfo.hpp"
#include "vktApiTests.hpp"
#include "vktPipelineTests.hpp"
#include "vktBindingModelTests.hpp"
void TestPackage::init (void)
{
- addChild(createInfoTests (m_testCtx));
addChild(api::createTests (m_testCtx));
addChild(pipeline::createTests (m_testCtx));
addChild(BindingModel::createTests (m_testCtx));
}
/*--------------------------------------------------------------------*//*!
+ * \brief Check if a value is a power-of-two.
+ * \param a Input value.
+ * \return True if input is a power-of-two value, false otherwise.
+ *
+ * \note Also returns true for zero.
+ *//*--------------------------------------------------------------------*/
+DE_INLINE deBool deIsPowerOfTwoSize (size_t a)
+{
+#if (DE_PTR_SIZE == 4)
+ return deIsPowerOfTwo32(a);
+#elif (DE_PTR_SIZE == 8)
+ return deIsPowerOfTwo64(a);
+#else
+# error "Invalid DE_PTR_SIZE"
+#endif
+}
+
+/*--------------------------------------------------------------------*//*!
* \brief Check if an integer is aligned to given power-of-two size.
* \param a Input value.
* \param align Alignment to check for.
return (void*)((val + align - 1) & ~(align - 1));
}
+/*--------------------------------------------------------------------*//*!
+ * \brief Align a size_t value to given power-of-two size.
+ * \param ptr Input value to align.
+ * \param align Alignment to check for (power-of-two).
+ * \return The aligned size (larger or equal to input).
+ *//*--------------------------------------------------------------------*/
+DE_INLINE size_t deAlignSize (size_t val, size_t align)
+{
+ DE_ASSERT(deIsPowerOfTwoSize(align));
+ return (val + align - 1) & ~(align - 1);
+}
+
extern const deInt8 g_clzLUT[256];
/*--------------------------------------------------------------------*//*!
#include <stdlib.h>
#include <string.h>
+#define DE_ALIGNED_MALLOC_POSIX 0
+#define DE_ALIGNED_MALLOC_WIN32 1
+#define DE_ALIGNED_MALLOC_GENERIC 2
+
+#if (DE_OS == DE_OS_UNIX) || ((DE_OS == DE_OS_ANDROID) && (DE_ANDROID_API >= 21))
+# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_POSIX
+# include <malloc.h>
+#elif (DE_OS == DE_OS_WIN32)
+# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_WIN32
+# include <malloc.h>
+#else
+# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_GENERIC
+#endif
+
#if defined(DE_VALGRIND_BUILD)
# include <valgrind/valgrind.h>
# if defined(HAVE_VALGRIND_MEMCHECK_H)
return ptr;
}
-void* deAlignedMalloc (size_t numBytes, deUint32 alignBytes)
-{
- size_t ptrSize = sizeof(void*);
- deUintptr origPtr = (deUintptr)deMalloc(numBytes + ptrSize + (size_t)alignBytes);
-
- DE_ASSERT(deInRange32(alignBytes, 0, 256) && deIsPowerOfTwo32(alignBytes));
-
- if (origPtr)
- {
- deUintptr alignedPtr = (deUintptr)deAlignPtr((void*)(origPtr + ptrSize), (deUintptr)alignBytes);
- deUintptr ptrPtr = (alignedPtr - ptrSize);
- *(deUintptr*)ptrPtr = origPtr;
- return (void*)alignedPtr;
- }
- else
- return DE_NULL;
-}
-
/*--------------------------------------------------------------------*//*!
* \brief Reallocate a chunk of memory.
* \param ptr Pointer to previously allocated memory block
free(ptr);
}
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+
+typedef struct AlignedAllocHeader_s
+{
+ void* basePtr;
+ size_t numBytes;
+} AlignedAllocHeader;
+
+DE_INLINE AlignedAllocHeader* getAlignedAllocHeader (void* ptr)
+{
+ const size_t hdrSize = sizeof(AlignedAllocHeader);
+ const deUintptr hdrAddr = (deUintptr)ptr - hdrSize;
+
+ return (AlignedAllocHeader*)hdrAddr;
+}
+
+#endif
+
+void* deAlignedMalloc (size_t numBytes, size_t alignBytes)
+{
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+ /* posix_memalign() requires that alignment must be 2^N * sizeof(void*) */
+ const size_t ptrAlignedAlign = deAlignSize(alignBytes, sizeof(void*));
+ void* ptr = DE_NULL;
+
+ DE_ASSERT(deIsPowerOfTwoSize(alignBytes) && deIsPowerOfTwoSize(ptrAlignedAlign / sizeof(void*)));
+
+ if (posix_memalign(&ptr, ptrAlignedAlign, numBytes) == 0)
+ {
+ DE_ASSERT(ptr);
+ return ptr;
+ }
+ else
+ {
+ DE_ASSERT(!ptr);
+ return DE_NULL;
+ }
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+ DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
+
+ return _aligned_malloc(numBytes, alignBytes);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+ void* const basePtr = deMalloc(numBytes + alignBytes + sizeof(AlignedAllocHeader));
+
+ DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
+
+ if (basePtr)
+ {
+ void* const alignedPtr = deAlignPtr((void*)((deUintptr)basePtr + sizeof(AlignedAllocHeader)), alignBytes);
+ AlignedAllocHeader* const hdr = getAlignedAllocHeader(alignedPtr);
+
+ hdr->basePtr = basePtr;
+ hdr->numBytes = numBytes;
+
+ return alignedPtr;
+ }
+ else
+ return DE_NULL;
+#else
+# error "Invalid DE_ALIGNED_MALLOC"
+#endif
+}
+
+void* deAlignedRealloc (void* ptr, size_t numBytes, size_t alignBytes)
+{
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+ return _aligned_realloc(ptr, numBytes, alignBytes);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC) || (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+ if (ptr)
+ {
+ if (numBytes > 0)
+ {
+# if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+ const size_t oldSize = getAlignedAllocHeader(ptr)->numBytes;
+# else /* DE_ALIGNED_MALLOC_GENERIC */
+ const size_t oldSize = malloc_usable_size(ptr);
+# endif
+
+ DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
+
+ if (oldSize < numBytes || oldSize > numBytes*2)
+ {
+ /* Create a new alloc if original is smaller, or more than twice the requested size */
+ void* const newPtr = deAlignedMalloc(numBytes, alignBytes);
+
+ if (newPtr)
+ {
+ const size_t copyBytes = numBytes < oldSize ? numBytes : oldSize;
+
+ deMemcpy(newPtr, ptr, copyBytes);
+ deAlignedFree(ptr);
+
+ return newPtr;
+ }
+ else
+ return DE_NULL;
+ }
+ else
+ return ptr;
+ }
+ else
+ {
+ deAlignedFree(ptr);
+ return DE_NULL;
+ }
+ }
+ else
+ return deAlignedMalloc(numBytes, alignBytes);
+
+#else
+# error "Invalid DE_ALIGNED_MALLOC"
+#endif
+}
+
void deAlignedFree (void* ptr)
{
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+ free(ptr);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+ _aligned_free(ptr);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
if (ptr)
{
- size_t ptrSize = sizeof(void*);
- deUintptr ptrPtr = (deUintptr)ptr - ptrSize;
- deUintptr origPtr = *(deUintptr*)ptrPtr;
- DE_ASSERT(ptrPtr - origPtr < 256);
- deFree((void*)origPtr);
+ AlignedAllocHeader* const hdr = getAlignedAllocHeader(ptr);
+
+ deFree(hdr->basePtr);
}
+#else
+# error "Invalid DE_ALIGNED_MALLOC"
+#endif
}
char* deStrdup (const char* str)
#endif
}
+void deMemory_selfTest (void)
+{
+ static const struct
+ {
+ size_t numBytes;
+ size_t alignment;
+ } s_alignedAllocCases[] =
+ {
+ { 1, 1 },
+ { 1, 2 },
+ { 1, 256 },
+ { 1, 4096 },
+ { 547389, 1 },
+ { 547389, 2 },
+ { 547389, 256 },
+ { 547389, 4096 },
+ { 52532, 1<<4 },
+ { 52532, 1<<10 },
+ { 52532, 1<<16 },
+ };
+ static const struct
+ {
+ size_t initialSize;
+ size_t newSize;
+ size_t alignment;
+ } s_alignedReallocCases[] =
+ {
+ { 1, 1, 1 },
+ { 1, 1, 2 },
+ { 1, 1, 256 },
+ { 1, 1, 4096 },
+ { 1, 1241, 1 },
+ { 1, 1241, 2 },
+ { 1, 1241, 256 },
+ { 1, 1241, 4096 },
+ { 547389, 234, 1 },
+ { 547389, 234, 2 },
+ { 547389, 234, 256 },
+ { 547389, 234, 4096 },
+ { 52532, 421523, 1<<4 },
+ { 52532, 421523, 1<<10 },
+ { 52532, 421523, 1<<16 },
+ };
+
+ int caseNdx;
+
+ for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedAllocCases); caseNdx++)
+ {
+ void* const ptr = deAlignedMalloc(s_alignedAllocCases[caseNdx].numBytes, s_alignedAllocCases[caseNdx].alignment);
+
+ DE_TEST_ASSERT(ptr);
+ DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedAllocCases[caseNdx].alignment));
+
+ deMemset(ptr, 0xaa, s_alignedAllocCases[caseNdx].numBytes);
+
+ deAlignedFree(ptr);
+ }
+
+ for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedReallocCases); caseNdx++)
+ {
+ void* const ptr = deAlignedMalloc(s_alignedReallocCases[caseNdx].initialSize, s_alignedReallocCases[caseNdx].alignment);
+
+ DE_TEST_ASSERT(ptr);
+ DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
+
+ deMemset(ptr, 0xaa, s_alignedReallocCases[caseNdx].initialSize);
+
+ {
+ void* const newPtr = deAlignedRealloc(ptr, s_alignedReallocCases[caseNdx].newSize, s_alignedReallocCases[caseNdx].alignment);
+ const size_t numPreserved = s_alignedReallocCases[caseNdx].newSize < s_alignedReallocCases[caseNdx].initialSize
+ ? s_alignedReallocCases[caseNdx].newSize
+ : s_alignedReallocCases[caseNdx].initialSize;
+ size_t off;
+
+ DE_TEST_ASSERT(newPtr);
+ DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
+
+ for (off = 0; off < numPreserved; off++)
+ DE_TEST_ASSERT(*((const deUint8*)newPtr + off) == 0xaa);
+
+ deAlignedFree(newPtr);
+ }
+ }
+}
+
DE_END_EXTERN_C
void* deRealloc (void* ptr, size_t numBytes);
void deFree (void* ptr);
-void* deAlignedMalloc (size_t numBytes, deUint32 alignBytes);
+void* deAlignedMalloc (size_t numBytes, size_t alignBytes);
+void* deAlignedRealloc(void* ptr, size_t numBytes, size_t alignBytes);
void deAlignedFree (void* ptr);
char* deStrdup (const char* str);
return memmove(dst, src, numBytes);
}
+void deMemory_selfTest (void);
+
DE_END_EXTERN_C
#endif /* _DEMEMORY_H */
endif ()
set(DECPP_SRCS
+ deAppendList.cpp
+ deAppendList.hpp
deArrayBuffer.cpp
deArrayBuffer.hpp
deArrayUtil.cpp
--- /dev/null
+/*-------------------------------------------------------------------------
+ * drawElements C++ Base Library
+ * -----------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Fast ordered append-only container
+ *//*--------------------------------------------------------------------*/
+
+#include "deAppendList.hpp"
+#include "deThread.hpp"
+#include "deSpinBarrier.hpp"
+#include "deSharedPtr.hpp"
+
+#include <vector>
+#include <algorithm>
+
+namespace de
+{
+
+namespace
+{
+
+using std::vector;
+
+struct TestElem
+{
+ deUint32 threadNdx;
+ deUint32 elemNdx;
+
+ TestElem (deUint32 threadNdx_, deUint32 elemNdx_)
+ : threadNdx (threadNdx_)
+ , elemNdx (elemNdx_)
+ {}
+
+ TestElem (void)
+ : threadNdx (0)
+ , elemNdx (0)
+ {}
+};
+
+struct SharedState
+{
+ deUint32 numElements;
+ SpinBarrier barrier;
+ AppendList<TestElem> testList;
+
+ SharedState (deUint32 numThreads, deUint32 numElements_, deUint32 numElementsHint)
+ : numElements (numElements_)
+ , barrier (numThreads)
+ , testList (numElementsHint)
+ {}
+};
+
+class TestThread : public Thread
+{
+public:
+ TestThread (SharedState* shared, deUint32 threadNdx)
+ : m_shared (shared)
+ , m_threadNdx (threadNdx)
+ {}
+
+ void run (void)
+ {
+ const deUint32 syncPerElems = 10000;
+
+ for (deUint32 elemNdx = 0; elemNdx < m_shared->numElements; elemNdx++)
+ {
+ if (elemNdx % syncPerElems == 0)
+ m_shared->barrier.sync(SpinBarrier::WAIT_MODE_AUTO);
+
+ m_shared->testList.append(TestElem(m_threadNdx, elemNdx));
+ }
+ }
+
+private:
+ SharedState* const m_shared;
+ const deUint32 m_threadNdx;
+};
+
+typedef SharedPtr<TestThread> TestThreadSp;
+
+void runAppendListTest (deUint32 numThreads, deUint32 numElements, deUint32 numElementsHint)
+{
+ SharedState sharedState (numThreads, numElements, numElementsHint);
+ vector<TestThreadSp> threads (numThreads);
+
+ for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+ {
+ threads[threadNdx] = TestThreadSp(new TestThread(&sharedState, threadNdx));
+ threads[threadNdx]->start();
+ }
+
+ for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+ threads[threadNdx]->join();
+
+ DE_TEST_ASSERT(sharedState.testList.size() == (size_t)numElements*(size_t)numThreads);
+
+ {
+ vector<deUint32> countByThread (numThreads);
+
+ std::fill(countByThread.begin(), countByThread.end(), 0);
+
+ for (AppendList<TestElem>::const_iterator elemIter = sharedState.testList.begin();
+ elemIter != sharedState.testList.end();
+ ++elemIter)
+ {
+ const TestElem& elem = *elemIter;
+
+ DE_TEST_ASSERT(de::inBounds(elem.threadNdx, 0u, numThreads));
+ DE_TEST_ASSERT(countByThread[elem.threadNdx] == elem.elemNdx);
+
+ countByThread[elem.threadNdx] += 1;
+ }
+
+ for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+ DE_TEST_ASSERT(countByThread[threadNdx] == numElements);
+ }
+}
+
+} // anonymous
+
+void AppendList_selfTest (void)
+{
+ // Single-threaded
+ runAppendListTest(1, 1000, 500);
+ runAppendListTest(1, 1000, 2000);
+ runAppendListTest(1, 35, 1);
+
+ // Multi-threaded
+ runAppendListTest(2, 10000, 500);
+ runAppendListTest(2, 100, 10);
+
+ if (deGetNumAvailableLogicalCores() >= 4)
+ {
+ runAppendListTest(4, 10000, 500);
+ runAppendListTest(4, 100, 10);
+ }
+}
+
+} // de
--- /dev/null
+#ifndef _DEAPPENDLIST_HPP
+#define _DEAPPENDLIST_HPP
+/*-------------------------------------------------------------------------
+ * drawElements C++ Base Library
+ * -----------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Fast ordered append-only container
+ *//*--------------------------------------------------------------------*/
+
+#include "deDefs.hpp"
+#include "deAtomic.h"
+#include "deThread.h"
+#include "deMemory.h"
+#include "deInt32.h"
+
+namespace de
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Fast ordered append-only container
+ *
+ * AppendList provides data structure for recording ordered list of elements
+ * quickly, while still providing good sequential read access speed.
+ * It is good for example logging.
+ *
+ * AppendList allocates memory in blocks of blockSize elements. Choosing
+ * too small blockSize will affect performance.
+ *
+ * Elements can be appended from multiple threads simultaneously but if
+ * current block runs out, allocation of next block will happen in a single
+ * thread and block others from inserting further elements until completed.
+ * For that reason shared AppendList should not be used if there is a lot
+ * of contention and instead per-thread AppendList's are recommended.
+ *//*--------------------------------------------------------------------*/
+template<typename ElementType>
+class AppendList
+{
+public:
+ AppendList (size_t blockSize);
+ ~AppendList (void);
+
+ void append (const ElementType& value);
+
+ size_t size (void) const { return m_numElements; }
+
+private:
+ AppendList (const AppendList<ElementType>&);
+ AppendList<ElementType>& operator= (const AppendList<ElementType>&);
+
+ struct Block
+ {
+ const size_t blockNdx;
+ ElementType* elements;
+ Block* volatile next;
+
+ Block (size_t blockNdx_, size_t size)
+ : blockNdx (blockNdx_)
+ , elements (reinterpret_cast<ElementType*>(deAlignedMalloc(sizeof(ElementType)*size,
+ deAlign32((deUint32)alignOf<ElementType>(), (deUint32)sizeof(void*)))))
+ , next (DE_NULL)
+ {
+ }
+
+ ~Block (void)
+ {
+ deAlignedFree(reinterpret_cast<void*>(elements));
+ }
+ };
+
+ const size_t m_blockSize;
+ volatile size_t m_numElements;
+ Block* m_first;
+ Block* volatile m_last;
+
+public:
+ template<typename CompatibleType>
+ class Iterator
+ {
+ public:
+ Iterator (Block* curBlock_, size_t blockSize_, size_t slotNdx_)
+ : m_curBlock (curBlock_)
+ , m_blockSize (blockSize_)
+ , m_slotNdx (slotNdx_)
+ {}
+
+ bool operator!= (const Iterator<CompatibleType>& other) const
+ {
+ return m_curBlock != other.m_curBlock || m_slotNdx != other.m_slotNdx;
+ }
+ bool operator== (const Iterator<CompatibleType>& other) const
+ {
+ return m_curBlock == other.m_curBlock && m_slotNdx == other.m_slotNdx;
+ }
+
+ Iterator<CompatibleType>& operator++ (void)
+ {
+ ++m_slotNdx;
+
+ if (m_slotNdx == m_blockSize)
+ {
+ m_slotNdx = 0;
+ m_curBlock = m_curBlock->next;
+ }
+
+ return *this;
+ }
+
+ Iterator<CompatibleType> operator++ (int) const
+ {
+ Iterator<CompatibleType> copy(*this);
+ return ++copy;
+ }
+
+ CompatibleType& operator* (void) const
+ {
+ return m_curBlock->elements[m_slotNdx];
+ }
+
+ operator Iterator<const CompatibleType> (void) const
+ {
+ return Iterator<const CompatibleType>(m_curBlock, m_blockSize, m_slotNdx);
+ }
+
+ private:
+ Block* m_curBlock;
+ size_t m_blockSize;
+ size_t m_slotNdx;
+ };
+
+ typedef Iterator<const ElementType> const_iterator;
+ typedef Iterator<ElementType> iterator;
+
+ const_iterator begin (void) const;
+ iterator begin (void);
+
+ const_iterator end (void) const;
+ iterator end (void);
+};
+
+template<typename ElementType>
+AppendList<ElementType>::AppendList (size_t blockSize)
+ : m_blockSize (blockSize)
+ , m_numElements (0)
+ , m_first (new Block(0, blockSize))
+ , m_last (m_first)
+{
+}
+
+template<typename ElementType>
+AppendList<ElementType>::~AppendList (void)
+{
+ size_t elementNdx = 0;
+ Block* curBlock = m_first;
+
+ while (curBlock)
+ {
+ Block* const delBlock = curBlock;
+
+ curBlock = delBlock->next;
+
+ // Call destructor for allocated elements
+ for (; elementNdx < min(m_numElements, delBlock->blockNdx*m_blockSize); ++elementNdx)
+ delBlock->elements[elementNdx%m_blockSize].~ElementType();
+
+ delete delBlock;
+ }
+}
+
+template<typename ElementType>
+void AppendList<ElementType>::append (const ElementType& value)
+{
+ // Fetch curBlock first before allocating slot. Otherwise m_last might get updated before
+ // this thread gets chance of reading it, leading to curBlock->blockNdx > blockNdx.
+ Block* curBlock = m_last;
+
+ deMemoryReadWriteFence();
+
+ {
+ const size_t elementNdx = deAtomicIncrementUSize(&m_numElements) - 1;
+ const size_t blockNdx = elementNdx / m_blockSize;
+ const size_t slotNdx = elementNdx - (blockNdx * m_blockSize);
+
+ while (curBlock->blockNdx != blockNdx)
+ {
+ if (curBlock->next)
+ curBlock = curBlock->next;
+ else
+ {
+ // Other thread(s) are currently allocating additional block(s)
+ deYield();
+ }
+ }
+
+ // Did we allocate last slot? If so, add a new block
+ if (slotNdx+1 == m_blockSize)
+ {
+ Block* const newBlock = new Block(blockNdx+1, m_blockSize);
+
+ deMemoryReadWriteFence();
+
+ // At this point if any other thread is trying to allocate more blocks
+ // they are being blocked by curBlock->next being null. This guarantees
+ // that this thread has exclusive modify access to m_last.
+ m_last = newBlock;
+ deMemoryReadWriteFence();
+
+ // At this point other threads might have skipped to newBlock, but we
+ // still have exclusive modify access to curBlock->next.
+ curBlock->next = newBlock;
+ deMemoryReadWriteFence();
+ }
+
+ new (&curBlock->elements[slotNdx]) ElementType(value);
+ }
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::const_iterator AppendList<ElementType>::begin (void) const
+{
+ return const_iterator(m_first, m_blockSize, 0);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::iterator AppendList<ElementType>::begin (void)
+{
+ return iterator(m_first, m_blockSize, 0);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::const_iterator AppendList<ElementType>::end (void) const
+{
+ return const_iterator(m_last, m_blockSize, m_numElements%m_blockSize);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::iterator AppendList<ElementType>::end (void)
+{
+ return iterator(m_last, m_blockSize, m_numElements%m_blockSize);
+}
+
+void AppendList_selfTest (void);
+
+} // de
+
+#endif // _DEAPPENDLIST_HPP
namespace de
{
-//!< Compute absolute value of x.
+//! Compute absolute value of x.
template<typename T> inline T abs (T x) { return x < T(0) ? -x : x; }
-//!< Get minimum of x and y.
+//! Get minimum of x and y.
template<typename T> inline T min (T x, T y) { return x <= y ? x : y; }
-//!< Get maximum of x and y.
+//! Get maximum of x and y.
template<typename T> inline T max (T x, T y) { return x >= y ? x : y; }
-//!< Clamp x in range a <= x <= b.
+//! Clamp x in range a <= x <= b.
template<typename T> inline T clamp (T x, T a, T b) { DE_ASSERT(a <= b); return x < a ? a : (x > b ? b : x); }
-//!< Test if x is in bounds a <= x < b.
+//! Test if x is in bounds a <= x < b.
template<typename T> inline bool inBounds (T x, T a, T b) { return a <= x && x < b; }
-//!< Test if x is in range a <= x <= b.
+//! Test if x is in range a <= x <= b.
template<typename T> inline bool inRange (T x, T a, T b) { return a <= x && x <= b; }
//! Helper for DE_CHECK() macros.
inline void operator() (T* ptr) const { delete[] ptr; }
};
+//! Get required memory alignment for type
+template<typename T>
+size_t alignOf (void)
+{
+ struct PaddingCheck { deUint8 b; T t; };
+ return (size_t)DE_OFFSET_OF(PaddingCheck, t);
+}
+
} // de
/*--------------------------------------------------------------------*//*!
#include "deInt32.h"
#include "deMath.h"
#include "deSha1.h"
+#include "deMemory.h"
// decpp
#include "deBlockBuffer.hpp"
#include "deStringUtil.hpp"
#include "deSpinBarrier.hpp"
#include "deSTLUtil.hpp"
+#include "deAppendList.hpp"
namespace dit
{
addChild(new SelfCheckCase(m_testCtx, "int32", "deInt32_selfTest()", deInt32_selfTest));
addChild(new SelfCheckCase(m_testCtx, "math", "deMath_selfTest()", deMath_selfTest));
addChild(new SelfCheckCase(m_testCtx, "sha1", "deSha1_selfTest()", deSha1_selfTest));
+ addChild(new SelfCheckCase(m_testCtx, "memory", "deMemory_selfTest()", deMemory_selfTest));
}
};
addChild(new SelfCheckCase(m_testCtx, "string_util", "de::StringUtil_selfTest()", de::StringUtil_selfTest));
addChild(new SelfCheckCase(m_testCtx, "spin_barrier", "de::SpinBarrier_selfTest()", de::SpinBarrier_selfTest));
addChild(new SelfCheckCase(m_testCtx, "stl_util", "de::STLUtil_selfTest()", de::STLUtil_selfTest));
+ addChild(new SelfCheckCase(m_testCtx, "append_list", "de::AppendList_selfTest()", de::AppendList_selfTest));
}
};