/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 The Khronos Group Inc. * * 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 Synchronization operation abstraction *//*--------------------------------------------------------------------*/ #include "vktSynchronizationOperation.hpp" #include "vkDefs.hpp" #include "vktTestCase.hpp" #include "vktTestCaseUtil.hpp" #include "vkRef.hpp" #include "vkRefUtil.hpp" #include "vkMemUtil.hpp" #include "vkBarrierUtil.hpp" #include "vkQueryUtil.hpp" #include "vkTypeUtil.hpp" #include "vkImageUtil.hpp" #include "vkBuilderUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "deUniquePtr.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include #include namespace vkt { namespace synchronization { namespace { using namespace vk; enum Constants { MAX_IMAGE_DIMENSION_2D = 0x1000u, MAX_UBO_RANGE = 0x4000u, MAX_UPDATE_BUFFER_SIZE = 0x10000u, }; enum BufferType { BUFFER_TYPE_UNIFORM, BUFFER_TYPE_STORAGE, }; enum AccessMode { ACCESS_MODE_READ, ACCESS_MODE_WRITE, }; enum PipelineType { PIPELINE_TYPE_GRAPHICS, PIPELINE_TYPE_COMPUTE, }; static const char* const s_perVertexBlock = "gl_PerVertex {\n" " vec4 gl_Position;\n" "}"; static const SyncInfo emptySyncInfo = { 0, // VkPipelineStageFlags stageMask; 0, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; std::string getShaderStageName(VkShaderStageFlagBits stage) { switch (stage) { default: DE_FATAL("Unhandled stage!"); return ""; case VK_SHADER_STAGE_COMPUTE_BIT: return "compute"; case VK_SHADER_STAGE_FRAGMENT_BIT: return "fragment"; case VK_SHADER_STAGE_VERTEX_BIT: return "vertex"; case VK_SHADER_STAGE_GEOMETRY_BIT: return "geometry"; case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return "tess_control"; case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return "tess_eval"; } } //! A pipeline that can be embedded inside an operation. class Pipeline { public: virtual ~Pipeline (void) {} virtual void recordCommands (OperationContext& context, const VkCommandBuffer cmdBuffer, const VkDescriptorSet descriptorSet) = 0; }; //! Vertex data that covers the whole viewport with two triangles. class VertexGrid { public: VertexGrid (OperationContext& context) : m_vertexFormat (VK_FORMAT_R32G32B32A32_SFLOAT) , m_vertexStride (tcu::getPixelSize(mapVkFormat(m_vertexFormat))) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); // Vertex positions { m_vertexData.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); m_vertexData.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); m_vertexData.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); m_vertexData.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); m_vertexData.push_back(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); m_vertexData.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); } { const VkDeviceSize vertexDataSizeBytes = m_vertexData.size() * sizeof(m_vertexData[0]); m_vertexBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible)); DE_ASSERT(sizeof(m_vertexData[0]) == m_vertexStride); { const Allocation& alloc = m_vertexBuffer->getAllocation(); deMemcpy(alloc.getHostPtr(), &m_vertexData[0], static_cast(vertexDataSizeBytes)); flushAlloc(vk, device, alloc); } } // Indices { const VkDeviceSize indexBufferSizeBytes = sizeof(deUint32) * m_vertexData.size(); const deUint32 numIndices = static_cast(m_vertexData.size()); m_indexBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(indexBufferSizeBytes, VK_BUFFER_USAGE_INDEX_BUFFER_BIT), MemoryRequirement::HostVisible)); { const Allocation& alloc = m_indexBuffer->getAllocation(); deUint32* const pData = static_cast(alloc.getHostPtr()); for (deUint32 i = 0; i < numIndices; ++i) pData[i] = i; flushAlloc(vk, device, alloc); } } } VkFormat getVertexFormat (void) const { return m_vertexFormat; } deUint32 getVertexStride (void) const { return m_vertexStride; } VkIndexType getIndexType (void) const { return VK_INDEX_TYPE_UINT32; } deUint32 getNumVertices (void) const { return static_cast(m_vertexData.size()); } deUint32 getNumIndices (void) const { return getNumVertices(); } VkBuffer getVertexBuffer (void) const { return **m_vertexBuffer; } VkBuffer getIndexBuffer (void) const { return **m_indexBuffer; } private: const VkFormat m_vertexFormat; const deUint32 m_vertexStride; std::vector m_vertexData; de::MovePtr m_vertexBuffer; de::MovePtr m_indexBuffer; }; //! Add flags for all shader stages required to support a particular stage (e.g. fragment requires vertex as well). VkShaderStageFlags getRequiredStages (const VkShaderStageFlagBits stage) { VkShaderStageFlags flags = 0; DE_ASSERT(stage == VK_SHADER_STAGE_COMPUTE_BIT || (stage & VK_SHADER_STAGE_COMPUTE_BIT) == 0); if (stage & VK_SHADER_STAGE_ALL_GRAPHICS) flags |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; if (stage & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) flags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; if (stage & VK_SHADER_STAGE_GEOMETRY_BIT) flags |= VK_SHADER_STAGE_GEOMETRY_BIT; if (stage & VK_SHADER_STAGE_COMPUTE_BIT) flags |= VK_SHADER_STAGE_COMPUTE_BIT; return flags; } //! Check that SSBO read/write is available and that all shader stages are supported. void requireFeaturesForSSBOAccess (OperationContext& context, const VkShaderStageFlags usedStages) { const InstanceInterface& vki = context.getInstanceInterface(); const VkPhysicalDevice physDevice = context.getPhysicalDevice(); FeatureFlags flags = (FeatureFlags)0; if (usedStages & VK_SHADER_STAGE_FRAGMENT_BIT) flags |= FEATURE_FRAGMENT_STORES_AND_ATOMICS; if (usedStages & (VK_SHADER_STAGE_ALL_GRAPHICS & (~VK_SHADER_STAGE_FRAGMENT_BIT))) flags |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS; if (usedStages & VK_SHADER_STAGE_GEOMETRY_BIT) flags |= FEATURE_GEOMETRY_SHADER; if (usedStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) flags |= FEATURE_TESSELLATION_SHADER; requireFeatures(vki, physDevice, flags); } Data getHostBufferData (const OperationContext& context, const Buffer& hostBuffer, const VkDeviceSize size) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const Allocation& alloc = hostBuffer.getAllocation(); const Data data = { static_cast(size), // std::size_t size; static_cast(alloc.getHostPtr()), // const deUint8* data; }; invalidateAlloc(vk, device, alloc); return data; } void setHostBufferData (const OperationContext& context, const Buffer& hostBuffer, const Data& data) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const Allocation& alloc = hostBuffer.getAllocation(); deMemcpy(alloc.getHostPtr(), data.data, data.size); flushAlloc(vk, device, alloc); } void assertValidShaderStage (const VkShaderStageFlagBits stage) { switch (stage) { case VK_SHADER_STAGE_VERTEX_BIT: case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: case VK_SHADER_STAGE_GEOMETRY_BIT: case VK_SHADER_STAGE_FRAGMENT_BIT: case VK_SHADER_STAGE_COMPUTE_BIT: // OK break; default: DE_FATAL("Invalid shader stage"); break; } } VkPipelineStageFlags pipelineStageFlagsFromShaderStageFlagBits (const VkShaderStageFlagBits shaderStage) { switch (shaderStage) { case VK_SHADER_STAGE_VERTEX_BIT: return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR; case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR; case VK_SHADER_STAGE_GEOMETRY_BIT: return VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR; case VK_SHADER_STAGE_FRAGMENT_BIT: return VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; case VK_SHADER_STAGE_COMPUTE_BIT: return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR; // Other usages are probably an error, so flag that. default: DE_FATAL("Invalid shader stage"); return (VkPipelineStageFlags)0; } } //! Fill destination buffer with a repeating pattern. void fillPattern (void* const pData, const VkDeviceSize size, bool useIndexPattern = false) { // There are two pattern options - most operations use primePattern, // indexPattern is only needed for testing vertex index bufffer. static const deUint8 primePattern[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 }; static const deUint32 indexPattern[] = { 0, 1, 2, 3, 4 }; const deUint8* pattern = (useIndexPattern ? reinterpret_cast(indexPattern) : primePattern); const deUint32 patternSize = static_cast(useIndexPattern ? DE_LENGTH_OF_ARRAY(indexPattern)*sizeof(deUint32) : DE_LENGTH_OF_ARRAY(primePattern)); deUint8* const pBytes = static_cast(pData); for (deUint32 i = 0; i < size; ++i) pBytes[i] = pattern[i % patternSize]; } //! Get size in bytes of a pixel buffer with given extent. VkDeviceSize getPixelBufferSize (const VkFormat format, const VkExtent3D& extent) { const int pixelSize = tcu::getPixelSize(mapVkFormat(format)); return (pixelSize * extent.width * extent.height * extent.depth); } //! Determine the size of a 2D image that can hold sizeBytes data. VkExtent3D get2DImageExtentWithSize (const VkDeviceSize sizeBytes, const deUint32 pixelSize) { const deUint32 size = static_cast(sizeBytes / pixelSize); DE_ASSERT(size <= MAX_IMAGE_DIMENSION_2D * MAX_IMAGE_DIMENSION_2D); return makeExtent3D( std::min(size, static_cast(MAX_IMAGE_DIMENSION_2D)), (size / MAX_IMAGE_DIMENSION_2D) + (size % MAX_IMAGE_DIMENSION_2D != 0 ? 1u : 0u), 1u); } VkClearValue makeClearValue (const VkFormat format) { if (isDepthStencilFormat(format)) return makeClearValueDepthStencil(0.4f, 21u); else { if (isIntFormat(format) || isUintFormat(format)) return makeClearValueColorU32(8u, 16u, 24u, 32u); else return makeClearValueColorF32(0.25f, 0.49f, 0.75f, 1.0f); } } void clearPixelBuffer (tcu::PixelBufferAccess& pixels, const VkClearValue& clearValue) { const tcu::TextureFormat format = pixels.getFormat(); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); if (format.order == tcu::TextureFormat::D) { for (int z = 0; z < pixels.getDepth(); z++) for (int y = 0; y < pixels.getHeight(); y++) for (int x = 0; x < pixels.getWidth(); x++) pixels.setPixDepth(clearValue.depthStencil.depth, x, y, z); } else if (format.order == tcu::TextureFormat::S) { for (int z = 0; z < pixels.getDepth(); z++) for (int y = 0; y < pixels.getHeight(); y++) for (int x = 0; x < pixels.getWidth(); x++) pixels.setPixStencil(clearValue.depthStencil.stencil, x, y, z); } else if (format.order == tcu::TextureFormat::DS) { for (int z = 0; z < pixels.getDepth(); z++) for (int y = 0; y < pixels.getHeight(); y++) for (int x = 0; x < pixels.getWidth(); x++) { pixels.setPixDepth(clearValue.depthStencil.depth, x, y, z); pixels.setPixStencil(clearValue.depthStencil.stencil, x, y, z); } } else if (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) { const tcu::UVec4 color (clearValue.color.uint32); for (int z = 0; z < pixels.getDepth(); z++) for (int y = 0; y < pixels.getHeight(); y++) for (int x = 0; x < pixels.getWidth(); x++) pixels.setPixel(color, x, y, z); } else { const tcu::Vec4 color (clearValue.color.float32); for (int z = 0; z < pixels.getDepth(); z++) for (int y = 0; y < pixels.getHeight(); y++) for (int x = 0; x < pixels.getWidth(); x++) pixels.setPixel(color, x, y, z); } } VkImageViewType getImageViewType (const VkImageType imageType) { switch (imageType) { case VK_IMAGE_TYPE_1D: return VK_IMAGE_VIEW_TYPE_1D; case VK_IMAGE_TYPE_2D: return VK_IMAGE_VIEW_TYPE_2D; case VK_IMAGE_TYPE_3D: return VK_IMAGE_VIEW_TYPE_3D; default: DE_FATAL("Unknown image type"); return VK_IMAGE_VIEW_TYPE_LAST; } } std::string getShaderImageType (const VkFormat format, const VkImageType imageType) { const tcu::TextureFormat texFormat = mapVkFormat(format); const std::string formatPart = tcu::getTextureChannelClass(texFormat.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" : tcu::getTextureChannelClass(texFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ? "i" : ""; switch (imageType) { case VK_IMAGE_TYPE_1D: return formatPart + "image1D"; case VK_IMAGE_TYPE_2D: return formatPart + "image2D"; case VK_IMAGE_TYPE_3D: return formatPart + "image3D"; default: DE_FATAL("Unknown image type"); return DE_NULL; } } std::string getShaderImageFormatQualifier (const VkFormat format) { const tcu::TextureFormat texFormat = mapVkFormat(format); const char* orderPart = DE_NULL; const char* typePart = DE_NULL; switch (texFormat.order) { case tcu::TextureFormat::R: orderPart = "r"; break; case tcu::TextureFormat::RG: orderPart = "rg"; break; case tcu::TextureFormat::RGB: orderPart = "rgb"; break; case tcu::TextureFormat::RGBA: orderPart = "rgba"; break; default: DE_FATAL("Unksupported texture channel order"); break; } switch (texFormat.type) { case tcu::TextureFormat::FLOAT: typePart = "32f"; break; case tcu::TextureFormat::HALF_FLOAT: typePart = "16f"; break; case tcu::TextureFormat::UNSIGNED_INT32: typePart = "32ui"; break; case tcu::TextureFormat::UNSIGNED_INT16: typePart = "16ui"; break; case tcu::TextureFormat::UNSIGNED_INT8: typePart = "8ui"; break; case tcu::TextureFormat::SIGNED_INT32: typePart = "32i"; break; case tcu::TextureFormat::SIGNED_INT16: typePart = "16i"; break; case tcu::TextureFormat::SIGNED_INT8: typePart = "8i"; break; case tcu::TextureFormat::UNORM_INT16: typePart = "16"; break; case tcu::TextureFormat::UNORM_INT8: typePart = "8"; break; case tcu::TextureFormat::SNORM_INT16: typePart = "16_snorm"; break; case tcu::TextureFormat::SNORM_INT8: typePart = "8_snorm"; break; default: DE_FATAL("Unksupported texture channel type"); break; } return std::string(orderPart) + typePart; } namespace FillUpdateBuffer { enum BufferOp { BUFFER_OP_FILL, BUFFER_OP_UPDATE, BUFFER_OP_UPDATE_WITH_INDEX_PATTERN, }; class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource, const BufferOp bufferOp) : m_context (context) , m_resource (resource) , m_fillValue (0x13) , m_bufferOp (bufferOp) { DE_ASSERT((m_resource.getBuffer().size % sizeof(deUint32)) == 0); DE_ASSERT(m_bufferOp == BUFFER_OP_FILL || m_resource.getBuffer().size <= MAX_UPDATE_BUFFER_SIZE); m_data.resize(static_cast(m_resource.getBuffer().size)); if (m_bufferOp == BUFFER_OP_FILL) { const std::size_t size = m_data.size() / sizeof(m_fillValue); deUint32* const pData = reinterpret_cast(&m_data[0]); for (deUint32 i = 0; i < size; ++i) pData[i] = m_fillValue; } else if (m_bufferOp == BUFFER_OP_UPDATE) { fillPattern(&m_data[0], m_data.size()); } else if(m_bufferOp == BUFFER_OP_UPDATE_WITH_INDEX_PATTERN) { fillPattern(&m_data[0], m_data.size(), true); } } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); if (m_bufferOp == BUFFER_OP_FILL) { vk.cmdFillBuffer(cmdBuffer, m_resource.getBuffer().handle, m_resource.getBuffer().offset, m_resource.getBuffer().size, m_fillValue); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask m_resource.getBuffer().handle, // VkBuffer buffer 0u, // VkDeviceSize offset m_resource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } else vk.cmdUpdateBuffer(cmdBuffer, m_resource.getBuffer().handle, m_resource.getBuffer().offset, m_resource.getBuffer().size, reinterpret_cast(&m_data[0])); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { const Data data = { m_data.size(), // std::size_t size; &m_data[0], // const deUint8* data; }; return data; } void setData (const Data& data) { deMemcpy(&m_data[0], data.data, data.size); } private: OperationContext& m_context; Resource& m_resource; std::vector m_data; const deUint32 m_fillValue; const BufferOp m_bufferOp; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const BufferOp bufferOp) : m_resourceDesc (resourceDesc) , m_bufferOp (bufferOp) { DE_ASSERT(m_bufferOp == BUFFER_OP_FILL || m_bufferOp == BUFFER_OP_UPDATE || m_bufferOp == BUFFER_OP_UPDATE_WITH_INDEX_PATTERN); DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_BUFFER || m_resourceDesc.type == RESOURCE_TYPE_INDEX_BUFFER); } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { return VK_BUFFER_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { if (m_bufferOp == BUFFER_OP_FILL && !context.isDeviceFunctionalitySupported("VK_KHR_maintenance1")) { return VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT; } return VK_QUEUE_TRANSFER_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource, m_bufferOp)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const BufferOp m_bufferOp; }; } // FillUpdateBuffer ns namespace CopyBuffer { class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource, const AccessMode mode) : m_context (context) , m_resource (resource) , m_mode (mode) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); const VkBufferUsageFlags hostBufferUsage = (m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : VK_BUFFER_USAGE_TRANSFER_SRC_BIT); m_hostBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(m_resource.getBuffer().size, hostBufferUsage), MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); if (m_mode == ACCESS_MODE_READ) deMemset(alloc.getHostPtr(), 0, static_cast(m_resource.getBuffer().size)); else fillPattern(alloc.getHostPtr(), m_resource.getBuffer().size); flushAlloc(vk, device, alloc); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferCopy copyRegion = makeBufferCopy(0u, 0u, m_resource.getBuffer().size); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); if (m_mode == ACCESS_MODE_READ) { vk.cmdCopyBuffer(cmdBuffer, m_resource.getBuffer().handle, **m_hostBuffer, 1u, ©Region); // Insert a barrier so copied data is available to the host const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_resource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } else { // Insert a barrier so buffer data is available to the device //const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( // VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask // VK_ACCESS_2_HOST_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask // VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask // VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask // **m_hostBuffer, // VkBuffer buffer // 0u, // VkDeviceSize offset // m_resource.getBuffer().size // VkDeviceSize size //); //VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); //synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyBuffer(cmdBuffer, **m_hostBuffer, m_resource.getBuffer().handle, 1u, ©Region); } } SyncInfo getInSyncInfo (void) const { const VkAccessFlags access = (m_mode == ACCESS_MODE_READ ? VK_ACCESS_2_TRANSFER_READ_BIT_KHR : 0); const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; access, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const VkAccessFlags access = (m_mode == ACCESS_MODE_WRITE ? VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR : 0); const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; access, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_resource.getBuffer().size); } void setData (const Data& data) { DE_ASSERT(m_mode == ACCESS_MODE_WRITE); setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; const AccessMode m_mode; de::MovePtr m_hostBuffer; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const AccessMode mode) : m_mode (mode) { DE_ASSERT(resourceDesc.type == RESOURCE_TYPE_BUFFER); DE_UNREF(resourceDesc); } deUint32 getInResourceUsageFlags (void) const { return m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : 0; } deUint32 getOutResourceUsageFlags (void) const { return m_mode == ACCESS_MODE_WRITE ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 0; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return VK_QUEUE_TRANSFER_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource, m_mode)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const AccessMode m_mode; }; class CopyImplementation : public Operation { public: CopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) { } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferCopy copyRegion = makeBufferCopy(0u, 0u, m_inResource.getBuffer().size); vk.cmdCopyBuffer(cmdBuffer, m_inResource.getBuffer().handle, m_outResource.getBuffer().handle, 1u, ©Region); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; de::MovePtr m_hostBuffer; }; class CopySupport : public OperationSupport { public: CopySupport (const ResourceDescription& resourceDesc) { DE_ASSERT(resourceDesc.type == RESOURCE_TYPE_BUFFER); DE_UNREF(resourceDesc); } deUint32 getInResourceUsageFlags (void) const { return VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } deUint32 getOutResourceUsageFlags (void) const { return VK_BUFFER_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return VK_QUEUE_TRANSFER_BIT; } de::MovePtr build (OperationContext&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } de::MovePtr build (OperationContext& context, Resource& inResource, Resource& outResource) const { return de::MovePtr(new CopyImplementation(context, inResource, outResource)); } }; } // CopyBuffer ns namespace CopyBlitResolveImage { class ImplementationBase : public Operation { public: //! Copy/Blit/Resolve etc. operation virtual void recordCopyCommand (const VkCommandBuffer cmdBuffer) = 0; //! Get source stage mask that is used during read - added to test synchronization2 new stage masks virtual VkPipelineStageFlags2KHR getReadSrcStageMask() const = 0; ImplementationBase (OperationContext& context, Resource& resource, const AccessMode mode) : m_context (context) , m_resource (resource) , m_mode (mode) , m_bufferSize (getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent)) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); if (m_mode == ACCESS_MODE_READ) deMemset(alloc.getHostPtr(), 0, static_cast(m_bufferSize)); else fillPattern(alloc.getHostPtr(), m_bufferSize); flushAlloc(vk, device, alloc); // Staging image m_image = de::MovePtr(new Image( vk, device, allocator, makeImageCreateInfo(m_resource.getImage().imageType, m_resource.getImage().extent, m_resource.getImage().format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), MemoryRequirement::Any)); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy bufferCopyRegion = makeBufferImageCopy(m_resource.getImage().extent, m_resource.getImage().subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Staging image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } if (m_mode == ACCESS_MODE_READ) { // Resource Image -> Staging image recordCopyCommand(cmdBuffer); // Staging image layout const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( getReadSrcStageMask(), // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR imageDependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &imageDependencyInfo); // Image -> Host buffer vk.cmdCopyImageToBuffer(cmdBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_hostBuffer, 1u, &bufferCopyRegion); // Insert a barrier so copied data is available to the host const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_bufferSize // VkDeviceSize size ); VkDependencyInfoKHR bufferDependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &bufferDependencyInfo); } else { // Host buffer -> Staging image vk.cmdCopyBufferToImage(cmdBuffer, **m_hostBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferCopyRegion); // Staging image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // Resource image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags2KHR)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_resource.getImage().handle, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // Staging image -> Resource Image recordCopyCommand(cmdBuffer); } } SyncInfo getInSyncInfo (void) const { const VkAccessFlags2KHR access = (m_mode == ACCESS_MODE_READ ? VK_ACCESS_2_TRANSFER_READ_BIT_KHR : VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR); const VkImageLayout layout = (m_mode == ACCESS_MODE_READ ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; access, // VkAccessFlags accessMask; layout, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const VkAccessFlags2KHR access = (m_mode == ACCESS_MODE_READ ? VK_ACCESS_2_TRANSFER_READ_BIT_KHR : VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR); const VkImageLayout layout = (m_mode == ACCESS_MODE_READ ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; access, // VkAccessFlags accessMask; layout, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_bufferSize); } void setData (const Data& data) { DE_ASSERT(m_mode == ACCESS_MODE_WRITE); setHostBufferData(m_context, *m_hostBuffer, data); } protected: OperationContext& m_context; Resource& m_resource; const AccessMode m_mode; const VkDeviceSize m_bufferSize; de::MovePtr m_hostBuffer; de::MovePtr m_image; }; VkOffset3D makeExtentOffset (const Resource& resource) { DE_ASSERT(resource.getType() == RESOURCE_TYPE_IMAGE); const VkExtent3D extent = resource.getImage().extent; switch (resource.getImage().imageType) { case VK_IMAGE_TYPE_1D: return makeOffset3D(extent.width, 1, 1); case VK_IMAGE_TYPE_2D: return makeOffset3D(extent.width, extent.height, 1); case VK_IMAGE_TYPE_3D: return makeOffset3D(extent.width, extent.height, extent.depth); default: DE_ASSERT(0); return VkOffset3D(); } } VkImageBlit makeBlitRegion (const Resource& resource) { const VkImageBlit blitRegion = { resource.getImage().subresourceLayers, // VkImageSubresourceLayers srcSubresource; { makeOffset3D(0, 0, 0), makeExtentOffset(resource) }, // VkOffset3D srcOffsets[2]; resource.getImage().subresourceLayers, // VkImageSubresourceLayers dstSubresource; { makeOffset3D(0, 0, 0), makeExtentOffset(resource) }, // VkOffset3D dstOffsets[2]; }; return blitRegion; } class BlitImplementation : public ImplementationBase { public: BlitImplementation (OperationContext& context, Resource& resource, const AccessMode mode) : ImplementationBase (context, resource, mode) , m_blitRegion (makeBlitRegion(m_resource)) { const InstanceInterface& vki = m_context.getInstanceInterface(); const VkPhysicalDevice physDevice = m_context.getPhysicalDevice(); const VkFormatProperties formatProps = getPhysicalDeviceFormatProperties(vki, physDevice, m_resource.getImage().format); const VkFormatFeatureFlags requiredFlags = (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT); // SRC and DST blit is required because both images are using the same format. if ((formatProps.optimalTilingFeatures & requiredFlags) != requiredFlags) TCU_THROW(NotSupportedError, "Format doesn't support blits"); } void recordCopyCommand (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); if (m_mode == ACCESS_MODE_READ) { // Resource Image -> Staging image vk.cmdBlitImage(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_blitRegion, VK_FILTER_NEAREST); } else { // Staging image -> Resource Image vk.cmdBlitImage(cmdBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_blitRegion, VK_FILTER_NEAREST); } } VkPipelineStageFlags2KHR getReadSrcStageMask() const { return (m_context.getSynchronizationType() == SynchronizationType::LEGACY) ? VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR : VK_PIPELINE_STAGE_2_BLIT_BIT_KHR; } private: const VkImageBlit m_blitRegion; }; template ImageCopyOrResolve makeImageRegion (const Resource& resource) { return { resource.getImage().subresourceLayers, // VkImageSubresourceLayers srcSubresource; makeOffset3D(0, 0, 0), // VkOffset3D srcOffset; resource.getImage().subresourceLayers, // VkImageSubresourceLayers dstSubresource; makeOffset3D(0, 0, 0), // VkOffset3D dstOffset; resource.getImage().extent, // VkExtent3D extent; }; } class CopyImplementation : public ImplementationBase { public: CopyImplementation (OperationContext& context, Resource& resource, const AccessMode mode) : ImplementationBase (context, resource, mode) , m_imageCopyRegion (makeImageRegion(m_resource)) { } void recordCopyCommand (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); if (m_mode == ACCESS_MODE_READ) { // Resource Image -> Staging image vk.cmdCopyImage(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_imageCopyRegion); } else { // Staging image -> Resource Image vk.cmdCopyImage(cmdBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_imageCopyRegion); } } VkPipelineStageFlags2KHR getReadSrcStageMask() const { return (m_context.getSynchronizationType() == SynchronizationType::LEGACY) ? VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR : VK_PIPELINE_STAGE_2_COPY_BIT_KHR; } private: const VkImageCopy m_imageCopyRegion; }; class ResolveImplementation : public ImplementationBase { public: ResolveImplementation(OperationContext& context, Resource& resource, const AccessMode mode) : ImplementationBase (context, resource, mode) , m_imageResolveRegion (makeImageRegion(resource)) { DE_ASSERT(m_mode == ACCESS_MODE_READ); } void recordCopyCommand(const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); // Resource Image -> Staging image vk.cmdResolveImage(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_imageResolveRegion); } VkPipelineStageFlags2KHR getReadSrcStageMask() const { return (m_context.getSynchronizationType() == SynchronizationType::LEGACY) ? VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR : VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR; } private: VkImageResolve m_imageResolveRegion; }; enum Type { TYPE_COPY, TYPE_BLIT, TYPE_RESOLVE, }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const Type type, const AccessMode mode) : m_type (type) , m_mode (mode) { DE_ASSERT(resourceDesc.type == RESOURCE_TYPE_IMAGE); const bool isDepthStencil = isDepthStencilFormat(resourceDesc.imageFormat); m_requiredQueueFlags = (isDepthStencil || m_type != TYPE_COPY ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_TRANSFER_BIT); // Don't blit depth/stencil images. DE_ASSERT(m_type != TYPE_BLIT || !isDepthStencil); } deUint32 getInResourceUsageFlags (void) const { return (m_mode == ACCESS_MODE_READ ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : 0); } deUint32 getOutResourceUsageFlags (void) const { return (m_mode == ACCESS_MODE_WRITE ? VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0); } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return m_requiredQueueFlags; } de::MovePtr build (OperationContext& context, Resource& resource) const { if (m_type == TYPE_COPY) return de::MovePtr(new CopyImplementation(context, resource, m_mode)); else if (m_type == TYPE_BLIT) return de::MovePtr(new BlitImplementation(context, resource, m_mode)); else return de::MovePtr(new ResolveImplementation(context, resource, m_mode)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const Type m_type; const AccessMode m_mode; VkQueueFlags m_requiredQueueFlags; }; class BlitCopyImplementation : public Operation { public: BlitCopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) , m_blitRegion (makeBlitRegion(m_inResource)) { DE_ASSERT(m_inResource.getType() == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_outResource.getType() == RESOURCE_TYPE_IMAGE); const InstanceInterface& vki = m_context.getInstanceInterface(); const VkPhysicalDevice physDevice = m_context.getPhysicalDevice(); const VkFormatProperties formatProps = getPhysicalDeviceFormatProperties(vki, physDevice, m_inResource.getImage().format); const VkFormatFeatureFlags requiredFlags = (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT); // SRC and DST blit is required because both images are using the same format. if ((formatProps.optimalTilingFeatures & requiredFlags) != requiredFlags) TCU_THROW(NotSupportedError, "Format doesn't support blits"); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags2KHR)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_outResource.getImage().handle, // VkImage image m_outResource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } vk.cmdBlitImage(cmdBuffer, m_inResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_outResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_blitRegion, VK_FILTER_NEAREST); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; const VkImageBlit m_blitRegion; }; class CopyCopyImplementation : public Operation { public: CopyCopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) , m_imageCopyRegion (makeImageRegion(m_inResource)) { DE_ASSERT(m_inResource.getType() == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_outResource.getType() == RESOURCE_TYPE_IMAGE); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_outResource.getImage().handle, // VkImage image m_outResource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } vk.cmdCopyImage(cmdBuffer, m_inResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_outResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &m_imageCopyRegion); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; const VkImageCopy m_imageCopyRegion; }; class CopySupport : public OperationSupport { public: CopySupport (const ResourceDescription& resourceDesc, const Type type) : m_type (type) { DE_ASSERT(resourceDesc.type == RESOURCE_TYPE_IMAGE); const bool isDepthStencil = isDepthStencilFormat(resourceDesc.imageFormat); m_requiredQueueFlags = (isDepthStencil || m_type == TYPE_BLIT ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_TRANSFER_BIT); // Don't blit depth/stencil images. DE_ASSERT(m_type != TYPE_BLIT || !isDepthStencil); } deUint32 getInResourceUsageFlags (void) const { return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return m_requiredQueueFlags; } de::MovePtr build (OperationContext&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } de::MovePtr build (OperationContext& context, Resource& inResource, Resource& outResource) const { if (m_type == TYPE_COPY) return de::MovePtr(new CopyCopyImplementation(context, inResource, outResource)); else return de::MovePtr(new BlitCopyImplementation(context, inResource, outResource)); } private: const Type m_type; VkQueueFlags m_requiredQueueFlags; }; } // CopyBlitImage ns namespace ShaderAccess { enum DispatchCall { DISPATCH_CALL_DISPATCH, DISPATCH_CALL_DISPATCH_INDIRECT, }; class GraphicsPipeline : public Pipeline { public: GraphicsPipeline (OperationContext& context, const VkShaderStageFlagBits stage, const std::string& shaderPrefix, const VkDescriptorSetLayout descriptorSetLayout) : m_vertices (context) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); const VkShaderStageFlags requiredStages = getRequiredStages(stage); // Color attachment m_colorFormat = VK_FORMAT_R8G8B8A8_UNORM; m_colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); m_colorImageExtent = makeExtent3D(16u, 16u, 1u); m_colorAttachmentImage = de::MovePtr(new Image(vk, device, allocator, makeImageCreateInfo(VK_IMAGE_TYPE_2D, m_colorImageExtent, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any)); // Pipeline m_colorAttachmentView = makeImageView (vk, device, **m_colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorImageSubresourceRange); m_renderPass = makeRenderPass (vk, device, m_colorFormat); m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, *m_colorAttachmentView, m_colorImageExtent.width, m_colorImageExtent.height); m_pipelineLayout = makePipelineLayout(vk, device, descriptorSetLayout); GraphicsPipelineBuilder pipelineBuilder; pipelineBuilder .setRenderSize (tcu::IVec2(m_colorImageExtent.width, m_colorImageExtent.height)) .setVertexInputSingleAttribute (m_vertices.getVertexFormat(), m_vertices.getVertexStride()) .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get(shaderPrefix + "vert"), DE_NULL) .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get(shaderPrefix + "frag"), DE_NULL); if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) pipelineBuilder .setPatchControlPoints (m_vertices.getNumVertices()) .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get(shaderPrefix + "tesc"), DE_NULL) .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get(shaderPrefix + "tese"), DE_NULL); if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) pipelineBuilder .setShader (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, context.getBinaryCollection().get(shaderPrefix + "geom"), DE_NULL); m_pipeline = pipelineBuilder.build(vk, device, *m_pipelineLayout, *m_renderPass, context.getPipelineCacheData()); } void recordCommands (OperationContext& context, const VkCommandBuffer cmdBuffer, const VkDescriptorSet descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(context.getSynchronizationType(), vk, DE_FALSE); // Change color attachment image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout **m_colorAttachmentImage, // VkImage image m_colorImageSubresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } { const VkRect2D renderArea = makeRect2D(m_colorImageExtent); const tcu::Vec4 clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, clearColor); } vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); { const VkDeviceSize vertexBufferOffset = 0ull; const VkBuffer vertexBuffer = m_vertices.getVertexBuffer(); vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset); } vk.cmdDraw(cmdBuffer, m_vertices.getNumVertices(), 1u, 0u, 0u); endRenderPass(vk, cmdBuffer); } private: const VertexGrid m_vertices; VkFormat m_colorFormat; de::MovePtr m_colorAttachmentImage; Move m_colorAttachmentView; VkExtent3D m_colorImageExtent; VkImageSubresourceRange m_colorImageSubresourceRange; Move m_renderPass; Move m_framebuffer; Move m_pipelineLayout; Move m_pipeline; }; class ComputePipeline : public Pipeline { public: ComputePipeline (OperationContext& context, const DispatchCall dispatchCall, const std::string& shaderPrefix, const VkDescriptorSetLayout descriptorSetLayout) : m_dispatchCall (dispatchCall) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); if (m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT) { m_indirectBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(sizeof(VkDispatchIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_indirectBuffer->getAllocation(); VkDispatchIndirectCommand* const pIndirectCommand = static_cast(alloc.getHostPtr()); pIndirectCommand->x = 1u; pIndirectCommand->y = 1u; pIndirectCommand->z = 1u; flushAlloc(vk, device, alloc); } const Unique shaderModule(createShaderModule(vk, device, context.getBinaryCollection().get(shaderPrefix + "comp"), (VkShaderModuleCreateFlags)0)); m_pipelineLayout = makePipelineLayout(vk, device, descriptorSetLayout); m_pipeline = makeComputePipeline(vk, device, *m_pipelineLayout, *shaderModule, DE_NULL, context.getPipelineCacheData()); } void recordCommands (OperationContext& context, const VkCommandBuffer cmdBuffer, const VkDescriptorSet descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); if (m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT) vk.cmdDispatchIndirect(cmdBuffer, **m_indirectBuffer, 0u); else vk.cmdDispatch(cmdBuffer, 1u, 1u, 1u); } private: const DispatchCall m_dispatchCall; de::MovePtr m_indirectBuffer; Move m_pipelineLayout; Move m_pipeline; }; //! Read/write operation on a UBO/SSBO in graphics/compute pipeline. class BufferImplementation : public Operation { public: BufferImplementation (OperationContext& context, Resource& resource, const VkShaderStageFlagBits stage, const BufferType bufferType, const std::string& shaderPrefix, const AccessMode mode, const PipelineType pipelineType, const DispatchCall dispatchCall) : m_context (context) , m_resource (resource) , m_stage (stage) , m_pipelineStage (pipelineStageFlagsFromShaderStageFlagBits(m_stage)) , m_bufferType (bufferType) , m_mode (mode) , m_dispatchCall (dispatchCall) { requireFeaturesForSSBOAccess (m_context, m_stage); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_resource.getBuffer().size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible)); // Init host buffer data { const Allocation& alloc = m_hostBuffer->getAllocation(); if (m_mode == ACCESS_MODE_READ) deMemset(alloc.getHostPtr(), 0, static_cast(m_resource.getBuffer().size)); else fillPattern(alloc.getHostPtr(), m_resource.getBuffer().size); flushAlloc(vk, device, alloc); } // Prepare descriptors { const VkDescriptorType bufferDescriptorType = (m_bufferType == BUFFER_TYPE_UNIFORM ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(bufferDescriptorType, m_stage) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_stage) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(bufferDescriptorType) .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorBufferInfo bufferInfo = makeDescriptorBufferInfo(m_resource.getBuffer().handle, m_resource.getBuffer().offset, m_resource.getBuffer().size); const VkDescriptorBufferInfo hostBufferInfo = makeDescriptorBufferInfo(**m_hostBuffer, 0u, m_resource.getBuffer().size); if (m_mode == ACCESS_MODE_READ) { DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), bufferDescriptorType, &bufferInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &hostBufferInfo) .update(vk, device); } else { DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &hostBufferInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo) .update(vk, device); } } // Create pipeline m_pipeline = (pipelineType == PIPELINE_TYPE_GRAPHICS ? de::MovePtr(new GraphicsPipeline(context, stage, shaderPrefix, *m_descriptorSetLayout)) : de::MovePtr(new ComputePipeline(context, m_dispatchCall, shaderPrefix, *m_descriptorSetLayout))); } void recordCommands (const VkCommandBuffer cmdBuffer) { m_pipeline->recordCommands(m_context, cmdBuffer, *m_descriptorSet); // Post draw/dispatch commands if (m_mode == ACCESS_MODE_READ) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Insert a barrier so data written by the shader is available to the host const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( m_pipelineStage, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_HOST_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_resource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } } SyncInfo getInSyncInfo (void) const { const VkAccessFlags2KHR accessFlags = (m_mode == ACCESS_MODE_READ ? (m_bufferType == BUFFER_TYPE_UNIFORM ? VK_ACCESS_2_UNIFORM_READ_BIT_KHR : VK_ACCESS_2_SHADER_READ_BIT_KHR) : VK_ACCESS_2_SHADER_WRITE_BIT_KHR); const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; accessFlags, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const VkAccessFlags accessFlags = m_mode == ACCESS_MODE_WRITE ? VK_ACCESS_2_SHADER_WRITE_BIT_KHR : 0; const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; accessFlags, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_resource.getBuffer().size); } void setData (const Data& data) { DE_ASSERT(m_mode == ACCESS_MODE_WRITE); setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; const VkShaderStageFlagBits m_stage; const VkPipelineStageFlags m_pipelineStage; const BufferType m_bufferType; const AccessMode m_mode; const DispatchCall m_dispatchCall; de::MovePtr m_hostBuffer; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; de::MovePtr m_pipeline; }; class ImageImplementation : public Operation { public: ImageImplementation (OperationContext& context, Resource& resource, const VkShaderStageFlagBits stage, const std::string& shaderPrefix, const AccessMode mode, const PipelineType pipelineType, const DispatchCall dispatchCall) : m_context (context) , m_resource (resource) , m_stage (stage) , m_pipelineStage (pipelineStageFlagsFromShaderStageFlagBits(m_stage)) , m_mode (mode) , m_dispatchCall (dispatchCall) , m_hostBufferSizeBytes (getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent)) { const DeviceInterface& vk = m_context.getDeviceInterface(); const InstanceInterface& vki = m_context.getInstanceInterface(); const VkDevice device = m_context.getDevice(); const VkPhysicalDevice physDevice = m_context.getPhysicalDevice(); Allocator& allocator = m_context.getAllocator(); // Image stores are always required, in either access mode. requireFeaturesForSSBOAccess(m_context, m_stage); // Some storage image formats may not be supported requireStorageImageSupport(vki, physDevice, m_resource.getImage().format); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_hostBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible)); // Init host buffer data { const Allocation& alloc = m_hostBuffer->getAllocation(); if (m_mode == ACCESS_MODE_READ) deMemset(alloc.getHostPtr(), 0, static_cast(m_hostBufferSizeBytes)); else fillPattern(alloc.getHostPtr(), m_hostBufferSizeBytes); flushAlloc(vk, device, alloc); } // Image resources { m_image = de::MovePtr(new Image(vk, device, allocator, makeImageCreateInfo(m_resource.getImage().imageType, m_resource.getImage().extent, m_resource.getImage().format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT), MemoryRequirement::Any)); if (m_mode == ACCESS_MODE_READ) { m_srcImage = &m_resource.getImage().handle; m_dstImage = &(**m_image); } else { m_srcImage = &(**m_image); m_dstImage = &m_resource.getImage().handle; } const VkImageViewType viewType = getImageViewType(m_resource.getImage().imageType); m_srcImageView = makeImageView(vk, device, *m_srcImage, viewType, m_resource.getImage().format, m_resource.getImage().subresourceRange); m_dstImageView = makeImageView(vk, device, *m_dstImage, viewType, m_resource.getImage().format, m_resource.getImage().subresourceRange); } // Prepare descriptors { m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_stage) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_stage) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorImageInfo srcImageInfo = makeDescriptorImageInfo(DE_NULL, *m_srcImageView, VK_IMAGE_LAYOUT_GENERAL); const VkDescriptorImageInfo dstImageInfo = makeDescriptorImageInfo(DE_NULL, *m_dstImageView, VK_IMAGE_LAYOUT_GENERAL); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &srcImageInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &dstImageInfo) .update(vk, device); } // Create pipeline m_pipeline = (pipelineType == PIPELINE_TYPE_GRAPHICS ? de::MovePtr(new GraphicsPipeline(context, stage, shaderPrefix, *m_descriptorSetLayout)) : de::MovePtr(new ComputePipeline(context, m_dispatchCall, shaderPrefix, *m_descriptorSetLayout))); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy bufferCopyRegion = makeBufferImageCopy(m_resource.getImage().extent, m_resource.getImage().subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Destination image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask m_pipelineStage, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout *m_dstImage, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // In write mode, source image must be filled with data. if (m_mode == ACCESS_MODE_WRITE) { // Layout for transfer { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout *m_srcImage, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // Host buffer -> Src image vk.cmdCopyBufferToImage(cmdBuffer, **m_hostBuffer, *m_srcImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferCopyRegion); // Layout for shader reading { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask m_pipelineStage, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_SHADER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout *m_srcImage, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } } // Execute shaders m_pipeline->recordCommands(m_context, cmdBuffer, *m_descriptorSet); // Post draw/dispatch commands if (m_mode == ACCESS_MODE_READ) { // Layout for transfer { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( m_pipelineStage, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout *m_dstImage, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // Dst image -> Host buffer vk.cmdCopyImageToBuffer(cmdBuffer, *m_dstImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_hostBuffer, 1u, &bufferCopyRegion); // Insert a barrier so data written by the shader is available to the host { const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_HOST_BIT, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_hostBufferSizeBytes // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } } } SyncInfo getInSyncInfo (void) const { const VkAccessFlags accessFlags = (m_mode == ACCESS_MODE_READ ? VK_ACCESS_2_SHADER_READ_BIT_KHR : 0); const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; accessFlags, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const VkAccessFlags accessFlags = (m_mode == ACCESS_MODE_WRITE ? VK_ACCESS_2_SHADER_WRITE_BIT_KHR : 0); const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; accessFlags, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_hostBufferSizeBytes); } void setData (const Data& data) { DE_ASSERT(m_mode == ACCESS_MODE_WRITE); setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; const VkShaderStageFlagBits m_stage; const VkPipelineStageFlags m_pipelineStage; const AccessMode m_mode; const DispatchCall m_dispatchCall; const VkDeviceSize m_hostBufferSizeBytes; de::MovePtr m_hostBuffer; de::MovePtr m_image; //! Additional image used as src or dst depending on operation mode. const VkImage* m_srcImage; const VkImage* m_dstImage; Move m_srcImageView; Move m_dstImageView; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; de::MovePtr m_pipeline; }; //! Create generic passthrough shaders with bits of custom code inserted in a specific shader stage. void initPassthroughPrograms (SourceCollections& programCollection, const std::string& shaderPrefix, const std::string& declCode, const std::string& mainCode, const VkShaderStageFlagBits stage) { const VkShaderStageFlags requiredStages = getRequiredStages(stage); if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) in vec4 v_in_position;\n" << "\n" << "out " << s_perVertexBlock << ";\n" << "\n" << (stage & VK_SHADER_STAGE_VERTEX_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << " gl_Position = v_in_position;\n" << (stage & VK_SHADER_STAGE_VERTEX_BIT ? mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "vert")) programCollection.glslSources.add(shaderPrefix + "vert") << glu::VertexSource(src.str()); } if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(vertices = 3) out;\n" << "\n" << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" << "\n" << "out " << s_perVertexBlock << " gl_out[];\n" << "\n" << (stage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << " gl_TessLevelInner[0] = 1.0;\n" << " gl_TessLevelInner[1] = 1.0;\n" << "\n" << " gl_TessLevelOuter[0] = 1.0;\n" << " gl_TessLevelOuter[1] = 1.0;\n" << " gl_TessLevelOuter[2] = 1.0;\n" << " gl_TessLevelOuter[3] = 1.0;\n" << "\n" << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" << (stage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? "\n" + mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "tesc")) programCollection.glslSources.add(shaderPrefix + "tesc") << glu::TessellationControlSource(src.str()); } if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(triangles, equal_spacing, ccw) in;\n" << "\n" << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" << "\n" << "out " << s_perVertexBlock << ";\n" << "\n" << (stage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << " vec3 px = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n" << " vec3 py = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n" << " vec3 pz = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n" << " gl_Position = vec4(px + py + pz, 1.0);\n" << (stage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT ? mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "tese")) programCollection.glslSources.add(shaderPrefix + "tese") << glu::TessellationEvaluationSource(src.str()); } if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(triangles) in;\n" << "layout(triangle_strip, max_vertices = 3) out;\n" << "\n" << "in " << s_perVertexBlock << " gl_in[];\n" << "\n" << "out " << s_perVertexBlock << ";\n" << "\n" << (stage & VK_SHADER_STAGE_GEOMETRY_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << " gl_Position = gl_in[0].gl_Position;\n" << " EmitVertex();\n" << "\n" << " gl_Position = gl_in[1].gl_Position;\n" << " EmitVertex();\n" << "\n" << " gl_Position = gl_in[2].gl_Position;\n" << " EmitVertex();\n" << (stage & VK_SHADER_STAGE_GEOMETRY_BIT ? "\n" + mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "geom")) programCollection.glslSources.add(shaderPrefix + "geom") << glu::GeometrySource(src.str()); } if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << (stage & VK_SHADER_STAGE_FRAGMENT_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << " o_color = vec4(1.0);\n" << (stage & VK_SHADER_STAGE_FRAGMENT_BIT ? "\n" + mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "frag")) programCollection.glslSources.add(shaderPrefix + "frag") << glu::FragmentSource(src.str()); } if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(local_size_x = 1) in;\n" << "\n" << (stage & VK_SHADER_STAGE_COMPUTE_BIT ? declCode + "\n" : "") << "void main (void)\n" << "{\n" << (stage & VK_SHADER_STAGE_COMPUTE_BIT ? mainCode : "") << "}\n"; if (!programCollection.glslSources.contains(shaderPrefix + "comp")) programCollection.glslSources.add(shaderPrefix + "comp") << glu::ComputeSource(src.str()); } } class BufferSupport : public OperationSupport { public: BufferSupport (const ResourceDescription& resourceDesc, const BufferType bufferType, const AccessMode mode, const VkShaderStageFlagBits stage, const DispatchCall dispatchCall = DISPATCH_CALL_DISPATCH) : m_resourceDesc (resourceDesc) , m_bufferType (bufferType) , m_mode (mode) , m_stage (stage) , m_shaderPrefix (std::string(m_mode == ACCESS_MODE_READ ? "read_" : "write_") + (m_bufferType == BUFFER_TYPE_UNIFORM ? "ubo_" : "ssbo_")) , m_dispatchCall (dispatchCall) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_BUFFER); DE_ASSERT(m_bufferType == BUFFER_TYPE_UNIFORM || m_bufferType == BUFFER_TYPE_STORAGE); DE_ASSERT(m_mode == ACCESS_MODE_READ || m_mode == ACCESS_MODE_WRITE); DE_ASSERT(m_mode == ACCESS_MODE_READ || m_bufferType == BUFFER_TYPE_STORAGE); DE_ASSERT(m_bufferType != BUFFER_TYPE_UNIFORM || m_resourceDesc.size.x() <= MAX_UBO_RANGE); DE_ASSERT(m_dispatchCall == DISPATCH_CALL_DISPATCH || m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT); assertValidShaderStage(m_stage); } void initPrograms (SourceCollections& programCollection) const { DE_ASSERT((m_resourceDesc.size.x() % sizeof(tcu::UVec4)) == 0); const std::string bufferTypeStr = (m_bufferType == BUFFER_TYPE_UNIFORM ? "uniform" : "buffer"); const int numVecElements = static_cast(m_resourceDesc.size.x() / sizeof(tcu::UVec4)); // std140 must be aligned to a multiple of 16 std::ostringstream declSrc; declSrc << "layout(set = 0, binding = 0, std140) readonly " << bufferTypeStr << " Input {\n" << " uvec4 data[" << numVecElements << "];\n" << "} b_in;\n" << "\n" << "layout(set = 0, binding = 1, std140) writeonly buffer Output {\n" << " uvec4 data[" << numVecElements << "];\n" << "} b_out;\n"; std::ostringstream copySrc; copySrc << " for (int i = 0; i < " << numVecElements << "; ++i) {\n" << " b_out.data[i] = b_in.data[i];\n" << " }\n"; initPassthroughPrograms(programCollection, m_shaderPrefix, declSrc.str(), copySrc.str(), m_stage); } deUint32 getInResourceUsageFlags (void) const { if (m_bufferType == BUFFER_TYPE_UNIFORM) return m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : 0; else return m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0; } deUint32 getOutResourceUsageFlags (void) const { if (m_bufferType == BUFFER_TYPE_UNIFORM) return m_mode == ACCESS_MODE_WRITE ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : 0; else return m_mode == ACCESS_MODE_WRITE ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return (m_stage == VK_SHADER_STAGE_COMPUTE_BIT ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT); } de::MovePtr build (OperationContext& context, Resource& resource) const { if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT) return de::MovePtr(new BufferImplementation(context, resource, m_stage, m_bufferType, m_shaderPrefix, m_mode, PIPELINE_TYPE_COMPUTE, m_dispatchCall)); else return de::MovePtr(new BufferImplementation(context, resource, m_stage, m_bufferType, m_shaderPrefix, m_mode, PIPELINE_TYPE_GRAPHICS, m_dispatchCall)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const BufferType m_bufferType; const AccessMode m_mode; const VkShaderStageFlagBits m_stage; const std::string m_shaderPrefix; const DispatchCall m_dispatchCall; }; class ImageSupport : public OperationSupport { public: ImageSupport (const ResourceDescription& resourceDesc, const AccessMode mode, const VkShaderStageFlagBits stage, const DispatchCall dispatchCall = DISPATCH_CALL_DISPATCH) : m_resourceDesc (resourceDesc) , m_mode (mode) , m_stage (stage) , m_shaderPrefix (m_mode == ACCESS_MODE_READ ? "read_image_" : "write_image_") , m_dispatchCall (dispatchCall) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_mode == ACCESS_MODE_READ || m_mode == ACCESS_MODE_WRITE); DE_ASSERT(m_dispatchCall == DISPATCH_CALL_DISPATCH || m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT); assertValidShaderStage(m_stage); } void initPrograms (SourceCollections& programCollection) const { const std::string imageFormat = getShaderImageFormatQualifier(m_resourceDesc.imageFormat); const std::string imageType = getShaderImageType(m_resourceDesc.imageFormat, m_resourceDesc.imageType); std::ostringstream declSrc; declSrc << "layout(set = 0, binding = 0, " << imageFormat << ") readonly uniform " << imageType << " srcImg;\n" << "layout(set = 0, binding = 1, " << imageFormat << ") writeonly uniform " << imageType << " dstImg;\n"; std::ostringstream mainSrc; if (m_resourceDesc.imageType == VK_IMAGE_TYPE_1D) mainSrc << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, x, imageLoad(srcImg, x));\n"; else if (m_resourceDesc.imageType == VK_IMAGE_TYPE_2D) mainSrc << " for (int y = 0; y < " << m_resourceDesc.size.y() << "; ++y)\n" << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, ivec2(x, y), imageLoad(srcImg, ivec2(x, y)));\n"; else if (m_resourceDesc.imageType == VK_IMAGE_TYPE_3D) mainSrc << " for (int z = 0; z < " << m_resourceDesc.size.z() << "; ++z)\n" << " for (int y = 0; y < " << m_resourceDesc.size.y() << "; ++y)\n" << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, ivec3(x, y, z), imageLoad(srcImg, ivec3(x, y, z)));\n"; else DE_ASSERT(0); initPassthroughPrograms(programCollection, m_shaderPrefix, declSrc.str(), mainSrc.str(), m_stage); } deUint32 getInResourceUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return (m_stage == VK_SHADER_STAGE_COMPUTE_BIT ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT); } de::MovePtr build (OperationContext& context, Resource& resource) const { if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT) return de::MovePtr(new ImageImplementation(context, resource, m_stage, m_shaderPrefix, m_mode, PIPELINE_TYPE_COMPUTE, m_dispatchCall)); else return de::MovePtr(new ImageImplementation(context, resource, m_stage, m_shaderPrefix, m_mode, PIPELINE_TYPE_GRAPHICS, m_dispatchCall)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const AccessMode m_mode; const VkShaderStageFlagBits m_stage; const std::string m_shaderPrefix; const DispatchCall m_dispatchCall; }; //! Copy operation on a UBO/SSBO in graphics/compute pipeline. class BufferCopyImplementation : public Operation { public: BufferCopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource, const VkShaderStageFlagBits stage, const BufferType bufferType, const std::string& shaderPrefix, const PipelineType pipelineType, const DispatchCall dispatchCall) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) , m_stage (stage) , m_pipelineStage (pipelineStageFlagsFromShaderStageFlagBits(m_stage)) , m_bufferType (bufferType) , m_dispatchCall (dispatchCall) { requireFeaturesForSSBOAccess (m_context, m_stage); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); // Prepare descriptors { const VkDescriptorType bufferDescriptorType = (m_bufferType == BUFFER_TYPE_UNIFORM ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(bufferDescriptorType, m_stage) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_stage) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(bufferDescriptorType) .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorBufferInfo inBufferInfo = makeDescriptorBufferInfo(m_inResource.getBuffer().handle, m_inResource.getBuffer().offset, m_inResource.getBuffer().size); const VkDescriptorBufferInfo outBufferInfo = makeDescriptorBufferInfo(m_outResource.getBuffer().handle, m_outResource.getBuffer().offset, m_outResource.getBuffer().size); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inBufferInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outBufferInfo) .update(vk, device); } // Create pipeline m_pipeline = (pipelineType == PIPELINE_TYPE_GRAPHICS ? de::MovePtr(new GraphicsPipeline(context, stage, shaderPrefix, *m_descriptorSetLayout)) : de::MovePtr(new ComputePipeline(context, m_dispatchCall, shaderPrefix, *m_descriptorSetLayout))); } void recordCommands (const VkCommandBuffer cmdBuffer) { m_pipeline->recordCommands(m_context, cmdBuffer, *m_descriptorSet); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; VK_ACCESS_2_SHADER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; const VkShaderStageFlagBits m_stage; const VkPipelineStageFlags m_pipelineStage; const BufferType m_bufferType; const DispatchCall m_dispatchCall; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; de::MovePtr m_pipeline; }; class CopyBufferSupport : public OperationSupport { public: CopyBufferSupport (const ResourceDescription& resourceDesc, const BufferType bufferType, const VkShaderStageFlagBits stage, const DispatchCall dispatchCall = DISPATCH_CALL_DISPATCH) : m_resourceDesc (resourceDesc) , m_bufferType (bufferType) , m_stage (stage) , m_shaderPrefix (std::string("copy_") + getShaderStageName(stage) + (m_bufferType == BUFFER_TYPE_UNIFORM ? "_ubo_" : "_ssbo_")) , m_dispatchCall (dispatchCall) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_BUFFER); DE_ASSERT(m_bufferType == BUFFER_TYPE_UNIFORM || m_bufferType == BUFFER_TYPE_STORAGE); DE_ASSERT(m_bufferType != BUFFER_TYPE_UNIFORM || m_resourceDesc.size.x() <= MAX_UBO_RANGE); DE_ASSERT(m_dispatchCall == DISPATCH_CALL_DISPATCH || m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT); assertValidShaderStage(m_stage); } void initPrograms (SourceCollections& programCollection) const { DE_ASSERT((m_resourceDesc.size.x() % sizeof(tcu::UVec4)) == 0); const std::string bufferTypeStr = (m_bufferType == BUFFER_TYPE_UNIFORM ? "uniform" : "buffer"); const int numVecElements = static_cast(m_resourceDesc.size.x() / sizeof(tcu::UVec4)); // std140 must be aligned to a multiple of 16 std::ostringstream declSrc; declSrc << "layout(set = 0, binding = 0, std140) readonly " << bufferTypeStr << " Input {\n" << " uvec4 data[" << numVecElements << "];\n" << "} b_in;\n" << "\n" << "layout(set = 0, binding = 1, std140) writeonly buffer Output {\n" << " uvec4 data[" << numVecElements << "];\n" << "} b_out;\n"; std::ostringstream copySrc; copySrc << " for (int i = 0; i < " << numVecElements << "; ++i) {\n" << " b_out.data[i] = b_in.data[i];\n" << " }\n"; initPassthroughPrograms(programCollection, m_shaderPrefix, declSrc.str(), copySrc.str(), m_stage); } deUint32 getInResourceUsageFlags (void) const { return (m_bufferType == BUFFER_TYPE_UNIFORM ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); } deUint32 getOutResourceUsageFlags (void) const { return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return (m_stage == VK_SHADER_STAGE_COMPUTE_BIT ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT); } de::MovePtr build (OperationContext&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } de::MovePtr build (OperationContext& context, Resource& inResource, Resource& outResource) const { if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT) return de::MovePtr(new BufferCopyImplementation(context, inResource, outResource, m_stage, m_bufferType, m_shaderPrefix, PIPELINE_TYPE_COMPUTE, m_dispatchCall)); else return de::MovePtr(new BufferCopyImplementation(context, inResource, outResource, m_stage, m_bufferType, m_shaderPrefix, PIPELINE_TYPE_GRAPHICS, m_dispatchCall)); } private: const ResourceDescription m_resourceDesc; const BufferType m_bufferType; const VkShaderStageFlagBits m_stage; const std::string m_shaderPrefix; const DispatchCall m_dispatchCall; }; class CopyImageImplementation : public Operation { public: CopyImageImplementation (OperationContext& context, Resource& inResource, Resource& outResource, const VkShaderStageFlagBits stage, const std::string& shaderPrefix, const PipelineType pipelineType, const DispatchCall dispatchCall) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) , m_stage (stage) , m_pipelineStage (pipelineStageFlagsFromShaderStageFlagBits(m_stage)) , m_dispatchCall (dispatchCall) { const DeviceInterface& vk = m_context.getDeviceInterface(); const InstanceInterface& vki = m_context.getInstanceInterface(); const VkDevice device = m_context.getDevice(); const VkPhysicalDevice physDevice = m_context.getPhysicalDevice(); // Image stores are always required, in either access mode. requireFeaturesForSSBOAccess(m_context, m_stage); // Some storage image formats may not be supported requireStorageImageSupport(vki, physDevice, m_inResource.getImage().format); // Image resources { const VkImageViewType viewType = getImageViewType(m_inResource.getImage().imageType); m_srcImageView = makeImageView(vk, device, m_inResource.getImage().handle, viewType, m_inResource.getImage().format, m_inResource.getImage().subresourceRange); m_dstImageView = makeImageView(vk, device, m_outResource.getImage().handle, viewType, m_outResource.getImage().format, m_outResource.getImage().subresourceRange); } // Prepare descriptors { m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_stage) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_stage) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorImageInfo srcImageInfo = makeDescriptorImageInfo(DE_NULL, *m_srcImageView, VK_IMAGE_LAYOUT_GENERAL); const VkDescriptorImageInfo dstImageInfo = makeDescriptorImageInfo(DE_NULL, *m_dstImageView, VK_IMAGE_LAYOUT_GENERAL); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &srcImageInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &dstImageInfo) .update(vk, device); } // Create pipeline m_pipeline = (pipelineType == PIPELINE_TYPE_GRAPHICS ? de::MovePtr(new GraphicsPipeline(context, stage, shaderPrefix, *m_descriptorSetLayout)) : de::MovePtr(new ComputePipeline(context, m_dispatchCall, shaderPrefix, *m_descriptorSetLayout))); } void recordCommands (const VkCommandBuffer cmdBuffer) { { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); const VkImageMemoryBarrier2KHR imageMemoryBarriers2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask m_pipelineStage, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout m_outResource.getImage().handle, // VkImage image m_outResource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo { VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR, // VkStructureType sType DE_NULL, // const void* pNext VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags 0u, // deUint32 memoryBarrierCount DE_NULL, // const VkMemoryBarrier2KHR* pMemoryBarriers 0u, // deUint32 bufferMemoryBarrierCount DE_NULL, // const VkBufferMemoryBarrier2KHR* pBufferMemoryBarriers 1, // deUint32 imageMemoryBarrierCount &imageMemoryBarriers2 // const VkImageMemoryBarrier2KHR* pImageMemoryBarriers }; synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // Execute shaders m_pipeline->recordCommands(m_context, cmdBuffer, *m_descriptorSet); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; VK_ACCESS_2_SHADER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { m_pipelineStage, // VkPipelineStageFlags stageMask; VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; const VkShaderStageFlagBits m_stage; const VkPipelineStageFlags m_pipelineStage; const DispatchCall m_dispatchCall; Move m_srcImageView; Move m_dstImageView; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; de::MovePtr m_pipeline; }; class CopyImageSupport : public OperationSupport { public: CopyImageSupport (const ResourceDescription& resourceDesc, const VkShaderStageFlagBits stage, const DispatchCall dispatchCall = DISPATCH_CALL_DISPATCH) : m_resourceDesc (resourceDesc) , m_stage (stage) , m_shaderPrefix (std::string("copy_image_") + getShaderStageName(stage) + "_") , m_dispatchCall (dispatchCall) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_dispatchCall == DISPATCH_CALL_DISPATCH || m_dispatchCall == DISPATCH_CALL_DISPATCH_INDIRECT); assertValidShaderStage(m_stage); } void initPrograms (SourceCollections& programCollection) const { const std::string imageFormat = getShaderImageFormatQualifier(m_resourceDesc.imageFormat); const std::string imageType = getShaderImageType(m_resourceDesc.imageFormat, m_resourceDesc.imageType); std::ostringstream declSrc; declSrc << "layout(set = 0, binding = 0, " << imageFormat << ") readonly uniform " << imageType << " srcImg;\n" << "layout(set = 0, binding = 1, " << imageFormat << ") writeonly uniform " << imageType << " dstImg;\n"; std::ostringstream mainSrc; if (m_resourceDesc.imageType == VK_IMAGE_TYPE_1D) mainSrc << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, x, imageLoad(srcImg, x));\n"; else if (m_resourceDesc.imageType == VK_IMAGE_TYPE_2D) mainSrc << " for (int y = 0; y < " << m_resourceDesc.size.y() << "; ++y)\n" << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, ivec2(x, y), imageLoad(srcImg, ivec2(x, y)));\n"; else if (m_resourceDesc.imageType == VK_IMAGE_TYPE_3D) mainSrc << " for (int z = 0; z < " << m_resourceDesc.size.z() << "; ++z)\n" << " for (int y = 0; y < " << m_resourceDesc.size.y() << "; ++y)\n" << " for (int x = 0; x < " << m_resourceDesc.size.x() << "; ++x)\n" << " imageStore(dstImg, ivec3(x, y, z), imageLoad(srcImg, ivec3(x, y, z)));\n"; else DE_ASSERT(0); initPassthroughPrograms(programCollection, m_shaderPrefix, declSrc.str(), mainSrc.str(), m_stage); } deUint32 getInResourceUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return (m_stage == VK_SHADER_STAGE_COMPUTE_BIT ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT); } de::MovePtr build (OperationContext&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } de::MovePtr build (OperationContext& context, Resource& inResource, Resource& outResource) const { if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT) return de::MovePtr(new CopyImageImplementation(context, inResource, outResource, m_stage, m_shaderPrefix, PIPELINE_TYPE_COMPUTE, m_dispatchCall)); else return de::MovePtr(new CopyImageImplementation(context, inResource, outResource, m_stage, m_shaderPrefix, PIPELINE_TYPE_GRAPHICS, m_dispatchCall)); } private: const ResourceDescription m_resourceDesc; const VkShaderStageFlagBits m_stage; const std::string m_shaderPrefix; const DispatchCall m_dispatchCall; }; class MSImageImplementation : public Operation { public: MSImageImplementation(OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_hostBufferSizeBytes(getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent)) { const DeviceInterface& vk = m_context.getDeviceInterface(); const InstanceInterface& vki = m_context.getInstanceInterface(); const VkDevice device = m_context.getDevice(); const VkPhysicalDevice physDevice = m_context.getPhysicalDevice(); const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice); Allocator& allocator = m_context.getAllocator(); requireStorageImageSupport(vki, physDevice, m_resource.getImage().format); if (!features.shaderStorageImageMultisample) TCU_THROW(NotSupportedError, "Using multisample images as storage is not supported"); VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(m_hostBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_hostBuffer = de::MovePtr(new Buffer(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); fillPattern(alloc.getHostPtr(), m_hostBufferSizeBytes); flushAlloc(vk, device, alloc); const ImageResource& image = m_resource.getImage(); const VkImageViewType viewType = getImageViewType(image.imageType); m_imageView = makeImageView(vk, device, image.handle, viewType, image.format, image.subresourceRange); // Prepare descriptors { m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorBufferInfo bufferInfo = makeDescriptorBufferInfo(**m_hostBuffer, 0u, m_hostBufferSizeBytes); const VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo) .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo) .update(vk, device); } // Create pipeline const Unique shaderModule(createShaderModule(vk, device, context.getBinaryCollection().get("comp"), (VkShaderModuleCreateFlags)0)); m_pipelineLayout = makePipelineLayout (vk, device, *m_descriptorSetLayout); m_pipeline = makeComputePipeline(vk, device, *m_pipelineLayout, *shaderModule, DE_NULL, context.getPipelineCacheData()); } void recordCommands(const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // change image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout m_resource.getImage().handle, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } // execute shader vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &*m_descriptorSet, 0u, DE_NULL); vk.cmdDispatch(cmdBuffer, m_resource.getImage().extent.width, m_resource.getImage().extent.height, 1u); } SyncInfo getInSyncInfo(void) const { DE_ASSERT(false); return emptySyncInfo; } SyncInfo getOutSyncInfo(void) const { return { VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; }; } Data getData(void) const { return getHostBufferData(m_context, *m_hostBuffer, m_hostBufferSizeBytes); } void setData(const Data&) { DE_ASSERT(false); } private: OperationContext& m_context; Resource& m_resource; Move m_imageView; const VkDeviceSize m_hostBufferSizeBytes; de::MovePtr m_hostBuffer; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; Move m_pipelineLayout; Move m_pipeline; }; class MSImageSupport : public OperationSupport { public: MSImageSupport(const ResourceDescription& resourceDesc) : m_resourceDesc (resourceDesc) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE); } void initPrograms (SourceCollections& programCollection) const { std::stringstream source; source << "#version 440\n" "\n" "layout(local_size_x = 1) in;\n" "layout(set = 0, binding = 0, std430) readonly buffer Input {\n" " uint data[];\n" "} inData;\n" "layout(set = 0, binding = 1, r32ui) writeonly uniform uimage2DMS msImage;\n" "\n" "void main (void)\n" "{\n" " int gx = int(gl_GlobalInvocationID.x);\n" " int gy = int(gl_GlobalInvocationID.y);\n" " uint value = inData.data[gy * " << m_resourceDesc.size.x() << " + gx];\n" " for (int sampleNdx = 0; sampleNdx < " << m_resourceDesc.imageSamples << "; ++sampleNdx)\n" " imageStore(msImage, ivec2(gx, gy), sampleNdx, uvec4(value));\n" "}\n"; programCollection.glslSources.add("comp") << glu::ComputeSource(source.str().c_str()); } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } VkQueueFlags getQueueFlags (const OperationContext&) const { return VK_QUEUE_COMPUTE_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new MSImageImplementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; }; } // ShaderAccess ns namespace CopyBufferToImage { class WriteImplementation : public Operation { public: WriteImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_bufferSize (getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent)) { DE_ASSERT(m_resource.getType() == RESOURCE_TYPE_IMAGE); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); fillPattern(alloc.getHostPtr(), m_bufferSize); flushAlloc(vk, device, alloc); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_resource.getImage().extent, m_resource.getImage().subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_resource.getImage().handle, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyBufferToImage(cmdBuffer, **m_hostBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_bufferSize); } void setData (const Data& data) { setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; de::MovePtr m_hostBuffer; const VkDeviceSize m_bufferSize; }; class ReadImplementation : public Operation { public: ReadImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_subresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) , m_subresourceLayers (makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)) { DE_ASSERT(m_resource.getType() == RESOURCE_TYPE_BUFFER); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; const deUint32 pixelSize = tcu::getPixelSize(mapVkFormat(format)); DE_ASSERT((m_resource.getBuffer().size % pixelSize) == 0); m_imageExtent = get2DImageExtentWithSize(m_resource.getBuffer().size, pixelSize); // there may be some unused space at the end // Copy destination image. m_image = de::MovePtr(new Image( vk, device, allocator, makeImageCreateInfo(VK_IMAGE_TYPE_2D, m_imageExtent, format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), MemoryRequirement::Any)); // Image data will be copied here, so it can be read on the host. m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_resource.getBuffer().size, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible)); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_imageExtent, m_subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Resource -> Image { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyBufferToImage(cmdBuffer, m_resource.getBuffer().handle, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region); } // Image -> Host buffer { const VkImageMemoryBarrier2KHR imageLayoutBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR layoutDependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageLayoutBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &layoutDependencyInfo); vk.cmdCopyImageToBuffer(cmdBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_hostBuffer, 1u, ©Region); const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_resource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR bufferDependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &bufferDependencyInfo); } } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { return emptySyncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_resource.getBuffer().size); } void setData (const Data& data) { setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; const VkImageSubresourceRange m_subresourceRange; const VkImageSubresourceLayers m_subresourceLayers; de::MovePtr m_hostBuffer; de::MovePtr m_image; VkExtent3D m_imageExtent; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const AccessMode mode) : m_mode (mode) , m_resourceType (resourceDesc.type) , m_requiredQueueFlags (resourceDesc.type == RESOURCE_TYPE_IMAGE && isDepthStencilFormat(resourceDesc.imageFormat) ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_TRANSFER_BIT) { // From spec: // Because depth or stencil aspect buffer to image copies may require format conversions on some implementations, // they are not supported on queues that do not support graphics. DE_ASSERT(m_mode == ACCESS_MODE_READ || m_mode == ACCESS_MODE_WRITE); DE_ASSERT(m_mode == ACCESS_MODE_READ || resourceDesc.type != RESOURCE_TYPE_BUFFER); DE_ASSERT(m_mode == ACCESS_MODE_WRITE || resourceDesc.type != RESOURCE_TYPE_IMAGE); } deUint32 getInResourceUsageFlags (void) const { if (m_resourceType == RESOURCE_TYPE_IMAGE) return m_mode == ACCESS_MODE_READ ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : 0; else return m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : 0; } deUint32 getOutResourceUsageFlags (void) const { if (m_resourceType == RESOURCE_TYPE_IMAGE) return m_mode == ACCESS_MODE_WRITE ? VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0; else return m_mode == ACCESS_MODE_WRITE ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 0; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return m_requiredQueueFlags; } de::MovePtr build (OperationContext& context, Resource& resource) const { if (m_mode == ACCESS_MODE_READ) return de::MovePtr(new ReadImplementation(context, resource)); else return de::MovePtr(new WriteImplementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const AccessMode m_mode; const enum ResourceType m_resourceType; const VkQueueFlags m_requiredQueueFlags; }; class CopyImplementation : public Operation { public: CopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) { DE_ASSERT(m_inResource.getType() == RESOURCE_TYPE_BUFFER); DE_ASSERT(m_outResource.getType() == RESOURCE_TYPE_IMAGE); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_outResource.getImage().extent, m_outResource.getImage().subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask m_inResource.getBuffer().handle, // VkBuffer buffer 0u, // VkDeviceSize offset m_inResource.getBuffer().size // VkDeviceSize size ); const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_outResource.getImage().handle, // VkImage image m_outResource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyBufferToImage(cmdBuffer, m_inResource.getBuffer().handle, m_outResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; }; class CopySupport : public OperationSupport { public: CopySupport (const ResourceDescription& resourceDesc) : m_resourceType (resourceDesc.type) , m_requiredQueueFlags (resourceDesc.type == RESOURCE_TYPE_IMAGE && isDepthStencilFormat(resourceDesc.imageFormat) ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_TRANSFER_BIT) { } deUint32 getInResourceUsageFlags (void) const { if (m_resourceType == RESOURCE_TYPE_IMAGE) return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; else return VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } deUint32 getOutResourceUsageFlags (void) const { if (m_resourceType == RESOURCE_TYPE_IMAGE) return VK_IMAGE_USAGE_TRANSFER_DST_BIT; else return VK_BUFFER_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return m_requiredQueueFlags; } de::MovePtr build (OperationContext&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } de::MovePtr build (OperationContext& context, Resource& inResource, Resource& outResource) const { return de::MovePtr(new CopyImplementation(context, inResource, outResource)); } private: const enum ResourceType m_resourceType; const VkQueueFlags m_requiredQueueFlags; }; } // CopyBufferToImage ns namespace CopyImageToBuffer { class WriteImplementation : public Operation { public: WriteImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_subresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) , m_subresourceLayers (makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)) { DE_ASSERT(m_resource.getType() == RESOURCE_TYPE_BUFFER); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; const deUint32 pixelSize = tcu::getPixelSize(mapVkFormat(format)); DE_ASSERT((m_resource.getBuffer().size % pixelSize) == 0); m_imageExtent = get2DImageExtentWithSize(m_resource.getBuffer().size, pixelSize); // Source data staging buffer m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_resource.getBuffer().size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); fillPattern(alloc.getHostPtr(), m_resource.getBuffer().size); flushAlloc(vk, device, alloc); // Source data image m_image = de::MovePtr(new Image( vk, device, allocator, makeImageCreateInfo(VK_IMAGE_TYPE_2D, m_imageExtent, format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), MemoryRequirement::Any)); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_imageExtent, m_subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Host buffer -> Image { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyBufferToImage(cmdBuffer, **m_hostBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region); } // Image -> Resource { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout **m_image, // VkImage image m_subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); vk.cmdCopyImageToBuffer(cmdBuffer, **m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_resource.getBuffer().handle, 1u, ©Region); } } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_resource.getBuffer().size); } void setData (const Data& data) { setHostBufferData(m_context, *m_hostBuffer, data); } private: OperationContext& m_context; Resource& m_resource; const VkImageSubresourceRange m_subresourceRange; const VkImageSubresourceLayers m_subresourceLayers; de::MovePtr m_hostBuffer; de::MovePtr m_image; VkExtent3D m_imageExtent; }; class ReadImplementation : public Operation { public: ReadImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_bufferSize (getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent)) { DE_ASSERT(m_resource.getType() == RESOURCE_TYPE_IMAGE); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_hostBuffer->getAllocation(); deMemset(alloc.getHostPtr(), 0, static_cast(m_bufferSize)); flushAlloc(vk, device, alloc); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_resource.getImage().extent, m_resource.getImage().subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); vk.cmdCopyImageToBuffer(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_hostBuffer, 1u, ©Region); // Insert a barrier so data written by the transfer is available to the host { const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset VK_WHOLE_SIZE // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { return emptySyncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_bufferSize); } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_resource; de::MovePtr m_hostBuffer; const VkDeviceSize m_bufferSize; }; class CopyImplementation : public Operation { public: CopyImplementation (OperationContext& context, Resource& inResource, Resource& outResource) : m_context (context) , m_inResource (inResource) , m_outResource (outResource) , m_subresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) , m_subresourceLayers (makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)) { DE_ASSERT(m_inResource.getType() == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_outResource.getType() == RESOURCE_TYPE_BUFFER); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBufferImageCopy copyRegion = makeBufferImageCopy(m_inResource.getImage().extent, m_subresourceLayers); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_inResource.getImage().handle, // VkImage image m_inResource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask m_outResource.getBuffer().handle, // VkBuffer buffer 0u, // VkDeviceSize offset m_outResource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } vk.cmdCopyImageToBuffer(cmdBuffer, m_inResource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_outResource.getBuffer().handle, 1u, ©Region); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { Data data = { 0, DE_NULL }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_inResource; Resource& m_outResource; const VkImageSubresourceRange m_subresourceRange; const VkImageSubresourceLayers m_subresourceLayers; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const AccessMode mode) : m_mode (mode) , m_requiredQueueFlags (resourceDesc.type == RESOURCE_TYPE_IMAGE && isDepthStencilFormat(resourceDesc.imageFormat) ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_TRANSFER_BIT) { DE_ASSERT(m_mode == ACCESS_MODE_READ || m_mode == ACCESS_MODE_WRITE); DE_ASSERT(m_mode == ACCESS_MODE_READ || resourceDesc.type != RESOURCE_TYPE_IMAGE); DE_ASSERT(m_mode == ACCESS_MODE_WRITE || resourceDesc.type != RESOURCE_TYPE_BUFFER); } deUint32 getInResourceUsageFlags (void) const { return m_mode == ACCESS_MODE_READ ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : 0; } deUint32 getOutResourceUsageFlags (void) const { return m_mode == ACCESS_MODE_WRITE ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 0; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return m_requiredQueueFlags; } de::MovePtr build (OperationContext& context, Resource& resource) const { if (m_mode == ACCESS_MODE_READ) return de::MovePtr(new ReadImplementation(context, resource)); else return de::MovePtr(new WriteImplementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const AccessMode m_mode; const VkQueueFlags m_requiredQueueFlags; }; } // CopyImageToBuffer ns namespace ClearImage { enum ClearMode { CLEAR_MODE_COLOR, CLEAR_MODE_DEPTH_STENCIL, }; class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource, const ClearMode mode) : m_context (context) , m_resource (resource) , m_clearValue (makeClearValue(m_resource.getImage().format)) , m_mode (mode) { const VkDeviceSize size = getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent); const VkExtent3D& extent = m_resource.getImage().extent; const VkFormat format = m_resource.getImage().format; const tcu::TextureFormat texFormat = mapVkFormat(format); m_data.resize(static_cast(size)); tcu::PixelBufferAccess imagePixels(texFormat, extent.width, extent.height, extent.depth, &m_data[0]); clearPixelBuffer(imagePixels, m_clearValue); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); VkPipelineStageFlags2KHR dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; if (m_context.getSynchronizationType() == SynchronizationType::SYNCHRONIZATION2) dstStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR; const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask dstStageMask, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout m_resource.getImage().handle, // VkImage image m_resource.getImage().subresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); if (m_mode == CLEAR_MODE_COLOR) vk.cmdClearColorImage(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_clearValue.color, 1u, &m_resource.getImage().subresourceRange); else vk.cmdClearDepthStencilImage(cmdBuffer, m_resource.getImage().handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_clearValue.depthStencil, 1u, &m_resource.getImage().subresourceRange); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { VkPipelineStageFlags2KHR stageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; if (m_context.getSynchronizationType() == SynchronizationType::SYNCHRONIZATION2) stageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR; return { stageMask, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout imageLayout; }; } Data getData (void) const { const Data data = { m_data.size(), // std::size_t size; &m_data[0], // const deUint8* data; }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_resource; std::vector m_data; const VkClearValue m_clearValue; const ClearMode m_mode; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const ClearMode mode) : m_resourceDesc (resourceDesc) , m_mode (mode) { DE_ASSERT(m_mode == CLEAR_MODE_COLOR || m_mode == CLEAR_MODE_DEPTH_STENCIL); DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE); DE_ASSERT(m_resourceDesc.imageAspect == VK_IMAGE_ASPECT_COLOR_BIT || (m_mode != CLEAR_MODE_COLOR)); DE_ASSERT((m_resourceDesc.imageAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) || (m_mode != CLEAR_MODE_DEPTH_STENCIL)); } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); if (m_mode == CLEAR_MODE_COLOR) return VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; else return VK_QUEUE_GRAPHICS_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource, m_mode)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const ClearMode m_mode; }; } // ClearImage ns namespace Draw { enum DrawCall { DRAW_CALL_DRAW, DRAW_CALL_DRAW_INDEXED, DRAW_CALL_DRAW_INDIRECT, DRAW_CALL_DRAW_INDEXED_INDIRECT, }; //! A write operation that is a result of drawing to an image. //! \todo Add support for depth/stencil too? class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource, const DrawCall drawCall) : m_context (context) , m_resource (resource) , m_drawCall (drawCall) , m_vertices (context) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); // Indirect buffer if (m_drawCall == DRAW_CALL_DRAW_INDIRECT) { m_indirectBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(sizeof(VkDrawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_indirectBuffer->getAllocation(); VkDrawIndirectCommand* const pIndirectCommand = static_cast(alloc.getHostPtr()); pIndirectCommand->vertexCount = m_vertices.getNumVertices(); pIndirectCommand->instanceCount = 1u; pIndirectCommand->firstVertex = 0u; pIndirectCommand->firstInstance = 0u; flushAlloc(vk, device, alloc); } else if (m_drawCall == DRAW_CALL_DRAW_INDEXED_INDIRECT) { m_indirectBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_indirectBuffer->getAllocation(); VkDrawIndexedIndirectCommand* const pIndirectCommand = static_cast(alloc.getHostPtr()); pIndirectCommand->indexCount = m_vertices.getNumIndices(); pIndirectCommand->instanceCount = 1u; pIndirectCommand->firstIndex = 0u; pIndirectCommand->vertexOffset = 0u; pIndirectCommand->firstInstance = 0u; flushAlloc(vk, device, alloc); } // Resource image is the color attachment m_colorFormat = m_resource.getImage().format; m_colorSubresourceRange = m_resource.getImage().subresourceRange; m_colorImage = m_resource.getImage().handle; m_attachmentExtent = m_resource.getImage().extent; // Pipeline m_colorAttachmentView = makeImageView (vk, device, m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange); m_renderPass = makeRenderPass (vk, device, m_colorFormat); m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, *m_colorAttachmentView, m_attachmentExtent.width, m_attachmentExtent.height); m_pipelineLayout = makePipelineLayout(vk, device); GraphicsPipelineBuilder pipelineBuilder; pipelineBuilder .setRenderSize (tcu::IVec2(m_attachmentExtent.width, m_attachmentExtent.height)) .setVertexInputSingleAttribute (m_vertices.getVertexFormat(), m_vertices.getVertexStride()) .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("draw_vert"), DE_NULL) .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("draw_frag"), DE_NULL); m_pipeline = pipelineBuilder.build(vk, device, *m_pipelineLayout, *m_renderPass, context.getPipelineCacheData()); // Set expected draw values m_expectedData.resize(static_cast(getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent))); tcu::PixelBufferAccess imagePixels(mapVkFormat(m_colorFormat), m_attachmentExtent.width, m_attachmentExtent.height, m_attachmentExtent.depth, &m_expectedData[0]); clearPixelBuffer(imagePixels, makeClearValue(m_colorFormat)); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Change color attachment image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout m_colorImage, // VkImage image m_colorSubresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } { const VkRect2D renderArea = makeRect2D(m_attachmentExtent); const tcu::Vec4 clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, clearColor); } vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); { const VkDeviceSize vertexBufferOffset = 0ull; const VkBuffer vertexBuffer = m_vertices.getVertexBuffer(); vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset); } if (m_drawCall == DRAW_CALL_DRAW_INDEXED || m_drawCall == DRAW_CALL_DRAW_INDEXED_INDIRECT) vk.cmdBindIndexBuffer(cmdBuffer, m_vertices.getIndexBuffer(), 0u, m_vertices.getIndexType()); switch (m_drawCall) { case DRAW_CALL_DRAW: vk.cmdDraw(cmdBuffer, m_vertices.getNumVertices(), 1u, 0u, 0u); break; case DRAW_CALL_DRAW_INDEXED: vk.cmdDrawIndexed(cmdBuffer, m_vertices.getNumIndices(), 1u, 0u, 0, 0u); break; case DRAW_CALL_DRAW_INDIRECT: vk.cmdDrawIndirect(cmdBuffer, **m_indirectBuffer, 0u, 1u, 0u); break; case DRAW_CALL_DRAW_INDEXED_INDIRECT: vk.cmdDrawIndexedIndirect(cmdBuffer, **m_indirectBuffer, 0u, 1u, 0u); break; } endRenderPass(vk, cmdBuffer); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { const Data data = { m_expectedData.size(), // std::size_t size; &m_expectedData[0], // const deUint8* data; }; return data; } void setData (const Data& data) { DE_ASSERT(m_expectedData.size() == data.size); deMemcpy(&m_expectedData[0], data.data, data.size); } private: OperationContext& m_context; Resource& m_resource; const DrawCall m_drawCall; const VertexGrid m_vertices; std::vector m_expectedData; de::MovePtr m_indirectBuffer; VkFormat m_colorFormat; VkImage m_colorImage; Move m_colorAttachmentView; VkImageSubresourceRange m_colorSubresourceRange; VkExtent3D m_attachmentExtent; Move m_renderPass; Move m_framebuffer; Move m_pipelineLayout; Move m_pipeline; }; template std::string toString (const T (&values)[N]) { std::ostringstream str; for (std::size_t i = 0; i < N; ++i) str << (i != 0 ? ", " : "") << values[i]; return str.str(); } class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc, const DrawCall drawCall) : m_resourceDesc (resourceDesc) , m_drawCall (drawCall) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE && m_resourceDesc.imageType == VK_IMAGE_TYPE_2D); DE_ASSERT(!isDepthStencilFormat(m_resourceDesc.imageFormat)); } void initPrograms (SourceCollections& programCollection) const { // Vertex { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) in vec4 v_in_position;\n" << "\n" << "out " << s_perVertexBlock << ";\n" << "\n" << "void main (void)\n" << "{\n" << " gl_Position = v_in_position;\n" << "}\n"; programCollection.glslSources.add("draw_vert") << glu::VertexSource(src.str()); } // Fragment { const VkClearValue clearValue = makeClearValue(m_resourceDesc.imageFormat); const bool isIntegerFormat = isIntFormat(m_resourceDesc.imageFormat) || isUintFormat(m_resourceDesc.imageFormat); const std::string colorType = (isIntegerFormat ? "uvec4" : "vec4"); std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) out " << colorType << " o_color;\n" << "\n" << "void main (void)\n" << "{\n" << " o_color = " << colorType << "(" << (isIntegerFormat ? toString(clearValue.color.uint32) : toString(clearValue.color.float32)) << ");\n" << "}\n"; programCollection.glslSources.add("draw_frag") << glu::FragmentSource(src.str()); } } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return VK_QUEUE_GRAPHICS_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource, m_drawCall)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const DrawCall m_drawCall; }; } // Draw ns namespace ClearAttachments { class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_clearValue (makeClearValue(m_resource.getImage().format)) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkDeviceSize size = getPixelBufferSize(m_resource.getImage().format, m_resource.getImage().extent); const VkExtent3D& extent = m_resource.getImage().extent; const VkFormat format = m_resource.getImage().format; const tcu::TextureFormat texFormat = mapVkFormat(format); const SyncInfo syncInfo = getOutSyncInfo(); m_data.resize(static_cast(size)); tcu::PixelBufferAccess imagePixels(texFormat, extent.width, extent.height, extent.depth, &m_data[0]); clearPixelBuffer(imagePixels, m_clearValue); m_attachmentView = makeImageView(vk, device, m_resource.getImage().handle, getImageViewType(m_resource.getImage().imageType), m_resource.getImage().format, m_resource.getImage().subresourceRange); switch (m_resource.getImage().subresourceRange.aspectMask) { case VK_IMAGE_ASPECT_COLOR_BIT: m_renderPass = makeRenderPass(vk, device, m_resource.getImage().format, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_DONT_CARE, syncInfo.imageLayout); break; case VK_IMAGE_ASPECT_STENCIL_BIT: case VK_IMAGE_ASPECT_DEPTH_BIT: m_renderPass = makeRenderPass(vk, device, VK_FORMAT_UNDEFINED, m_resource.getImage().format, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, syncInfo.imageLayout); break; default: DE_ASSERT(0); break; } m_frameBuffer = makeFramebuffer(vk, device, *m_renderPass, *m_attachmentView, m_resource.getImage().extent.width, m_resource.getImage().extent.height); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); if ((m_resource.getImage().subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { const VkImageMemoryBarrier imageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext 0u, // srcAccessMask VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // newLayout VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex m_resource.getImage().handle, // image m_resource.getImage().subresourceRange // subresourceRange }; vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier); } beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_frameBuffer, makeRect2D(0 ,0, m_resource.getImage().extent.width, m_resource.getImage().extent.height), m_clearValue); const VkClearAttachment clearAttachment = { m_resource.getImage().subresourceRange.aspectMask, // VkImageAspectFlags aspectMask; 0, // deUint32 colorAttachment; m_clearValue // VkClearValue clearValue; }; const VkRect2D rect2D = makeRect2D(m_resource.getImage().extent); const VkClearRect clearRect = { rect2D, // VkRect2D rect; 0u, // deUint32 baseArrayLayer; m_resource.getImage().subresourceLayers.layerCount // deUint32 layerCount; }; vk.cmdClearAttachments(cmdBuffer, 1, &clearAttachment, 1, &clearRect); endRenderPass(vk, cmdBuffer); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { SyncInfo syncInfo; syncInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; switch (m_resource.getImage().subresourceRange.aspectMask) { case VK_IMAGE_ASPECT_COLOR_BIT: syncInfo.accessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; syncInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; break; case VK_IMAGE_ASPECT_STENCIL_BIT: case VK_IMAGE_ASPECT_DEPTH_BIT: syncInfo.accessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; syncInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; break; default: DE_ASSERT(0); break; } return syncInfo; } Data getData (void) const { const Data data = { m_data.size(), // std::size_t size; &m_data[0], // const deUint8* data; }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_resource; std::vector m_data; const VkClearValue m_clearValue; Move m_attachmentView; Move m_renderPass; Move m_frameBuffer; }; class Support : public OperationSupport { public: Support (const ResourceDescription& resourceDesc) : m_resourceDesc (resourceDesc) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE); } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { switch (m_resourceDesc.imageAspect) { case VK_IMAGE_ASPECT_COLOR_BIT: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; case VK_IMAGE_ASPECT_STENCIL_BIT: case VK_IMAGE_ASPECT_DEPTH_BIT: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; default: DE_ASSERT(0); } return 0u; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return VK_QUEUE_GRAPHICS_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; }; } // ClearAttachments namespace IndirectBuffer { class GraphicsPipeline : public Pipeline { public: GraphicsPipeline (OperationContext& context, const ResourceType resourceType, const VkBuffer indirectBuffer, const std::string& shaderPrefix, const VkDescriptorSetLayout descriptorSetLayout) : m_resourceType (resourceType) , m_indirectBuffer (indirectBuffer) , m_vertices (context) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); // Color attachment m_colorFormat = VK_FORMAT_R8G8B8A8_UNORM; m_colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); m_colorImageExtent = makeExtent3D(16u, 16u, 1u); m_colorAttachmentImage = de::MovePtr(new Image(vk, device, allocator, makeImageCreateInfo(VK_IMAGE_TYPE_2D, m_colorImageExtent, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any)); // Pipeline m_colorAttachmentView = makeImageView (vk, device, **m_colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorImageSubresourceRange); m_renderPass = makeRenderPass (vk, device, m_colorFormat); m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, *m_colorAttachmentView, m_colorImageExtent.width, m_colorImageExtent.height); m_pipelineLayout = makePipelineLayout(vk, device, descriptorSetLayout); GraphicsPipelineBuilder pipelineBuilder; pipelineBuilder .setRenderSize (tcu::IVec2(m_colorImageExtent.width, m_colorImageExtent.height)) .setVertexInputSingleAttribute (m_vertices.getVertexFormat(), m_vertices.getVertexStride()) .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get(shaderPrefix + "vert"), DE_NULL) .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get(shaderPrefix + "frag"), DE_NULL); m_pipeline = pipelineBuilder.build(vk, device, *m_pipelineLayout, *m_renderPass, context.getPipelineCacheData()); } void recordCommands (OperationContext& context, const VkCommandBuffer cmdBuffer, const VkDescriptorSet descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(context.getSynchronizationType(), vk, DE_FALSE); // Change color attachment image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout **m_colorAttachmentImage, // VkImage image m_colorImageSubresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } { const VkRect2D renderArea = makeRect2D(m_colorImageExtent); const tcu::Vec4 clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, clearColor); } vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); { const VkDeviceSize vertexBufferOffset = 0ull; const VkBuffer vertexBuffer = m_vertices.getVertexBuffer(); vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset); } switch (m_resourceType) { case RESOURCE_TYPE_INDIRECT_BUFFER_DRAW: vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer, 0u, 1u, 0u); break; case RESOURCE_TYPE_INDIRECT_BUFFER_DRAW_INDEXED: vk.cmdBindIndexBuffer(cmdBuffer, m_vertices.getIndexBuffer(), 0u, m_vertices.getIndexType()); vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer, 0u, 1u, 0u); break; default: DE_ASSERT(0); break; } endRenderPass(vk, cmdBuffer); } private: const ResourceType m_resourceType; const VkBuffer m_indirectBuffer; const VertexGrid m_vertices; VkFormat m_colorFormat; de::MovePtr m_colorAttachmentImage; Move m_colorAttachmentView; VkExtent3D m_colorImageExtent; VkImageSubresourceRange m_colorImageSubresourceRange; Move m_renderPass; Move m_framebuffer; Move m_pipelineLayout; Move m_pipeline; }; class ComputePipeline : public Pipeline { public: ComputePipeline (OperationContext& context, const VkBuffer indirectBuffer, const std::string& shaderPrefix, const VkDescriptorSetLayout descriptorSetLayout) : m_indirectBuffer (indirectBuffer) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const Unique shaderModule(createShaderModule(vk, device, context.getBinaryCollection().get(shaderPrefix + "comp"), (VkShaderModuleCreateFlags)0)); m_pipelineLayout = makePipelineLayout(vk, device, descriptorSetLayout); m_pipeline = makeComputePipeline(vk, device, *m_pipelineLayout, *shaderModule, DE_NULL, context.getPipelineCacheData()); } void recordCommands (OperationContext& context, const VkCommandBuffer cmdBuffer, const VkDescriptorSet descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); vk.cmdDispatchIndirect(cmdBuffer, m_indirectBuffer, 0u); } private: const VkBuffer m_indirectBuffer; Move m_pipelineLayout; Move m_pipeline; }; //! Read indirect buffer by executing an indirect draw or dispatch command. class ReadImplementation : public Operation { public: ReadImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) , m_stage (resource.getType() == RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_VERTEX_BIT) , m_pipelineStage (pipelineStageFlagsFromShaderStageFlagBits(m_stage)) , m_hostBufferSizeBytes (sizeof(deUint32)) { requireFeaturesForSSBOAccess (m_context, m_stage); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); Allocator& allocator = m_context.getAllocator(); m_hostBuffer = de::MovePtr(new Buffer( vk, device, allocator, makeBufferCreateInfo(m_hostBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible)); // Init host buffer data { const Allocation& alloc = m_hostBuffer->getAllocation(); deMemset(alloc.getHostPtr(), 0, static_cast(m_hostBufferSizeBytes)); flushAlloc(vk, device, alloc); } // Prepare descriptors { m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_stage) .build(vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorBufferInfo hostBufferInfo = makeDescriptorBufferInfo(**m_hostBuffer, 0u, m_hostBufferSizeBytes); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &hostBufferInfo) .update(vk, device); } // Create pipeline m_pipeline = (m_resource.getType() == RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH ? de::MovePtr(new ComputePipeline(context, m_resource.getBuffer().handle, "read_ib_", *m_descriptorSetLayout)) : de::MovePtr(new GraphicsPipeline(context, m_resource.getType(), m_resource.getBuffer().handle, "read_ib_", *m_descriptorSetLayout))); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); m_pipeline->recordCommands(m_context, cmdBuffer, *m_descriptorSet); // Insert a barrier so data written by the shader is available to the host const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( m_pipelineStage, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_hostBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_hostBufferSizeBytes // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } SyncInfo getInSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { return emptySyncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_hostBuffer, m_hostBufferSizeBytes); } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_resource; const VkShaderStageFlagBits m_stage; const VkPipelineStageFlags m_pipelineStage; const VkDeviceSize m_hostBufferSizeBytes; de::MovePtr m_hostBuffer; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; de::MovePtr m_pipeline; }; //! Prepare indirect buffer for a draw/dispatch call. class WriteImplementation : public Operation { public: WriteImplementation (OperationContext& context, Resource& resource) : m_context (context) , m_resource (resource) { switch (m_resource.getType()) { case RESOURCE_TYPE_INDIRECT_BUFFER_DRAW: { m_drawIndirect.vertexCount = 6u; m_drawIndirect.instanceCount = 1u; m_drawIndirect.firstVertex = 0u; m_drawIndirect.firstInstance = 0u; m_indirectData = reinterpret_cast(&m_drawIndirect); m_expectedValue = 6u; } break; case RESOURCE_TYPE_INDIRECT_BUFFER_DRAW_INDEXED: { m_drawIndexedIndirect.indexCount = 6u; m_drawIndexedIndirect.instanceCount = 1u; m_drawIndexedIndirect.firstIndex = 0u; m_drawIndexedIndirect.vertexOffset = 0u; m_drawIndexedIndirect.firstInstance = 0u; m_indirectData = reinterpret_cast(&m_drawIndexedIndirect); m_expectedValue = 6u; } break; case RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH: { m_dispatchIndirect.x = 7u; m_dispatchIndirect.y = 2u; m_dispatchIndirect.z = 1u; m_indirectData = reinterpret_cast(&m_dispatchIndirect); m_expectedValue = 14u; } break; default: DE_ASSERT(0); break; } } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); vk.cmdUpdateBuffer(cmdBuffer, m_resource.getBuffer().handle, m_resource.getBuffer().offset, m_resource.getBuffer().size, m_indirectData); } SyncInfo getInSyncInfo (void) const { return emptySyncInfo; } SyncInfo getOutSyncInfo (void) const { const SyncInfo syncInfo = { VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, // VkPipelineStageFlags stageMask; VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } Data getData (void) const { const Data data = { sizeof(deUint32), // std::size_t size; reinterpret_cast(&m_expectedValue), // const deUint8* data; }; return data; } void setData (const Data&) { DE_ASSERT(0); } private: OperationContext& m_context; Resource& m_resource; VkDrawIndirectCommand m_drawIndirect; VkDrawIndexedIndirectCommand m_drawIndexedIndirect; VkDispatchIndirectCommand m_dispatchIndirect; deUint32* m_indirectData; deUint32 m_expectedValue; //! Side-effect value expected to be computed by a read (draw/dispatch) command. }; class ReadSupport : public OperationSupport { public: ReadSupport (const ResourceDescription& resourceDesc) : m_resourceDesc (resourceDesc) { DE_ASSERT(isIndirectBuffer(m_resourceDesc.type)); } void initPrograms (SourceCollections& programCollection) const { std::ostringstream decl; decl << "layout(set = 0, binding = 0, std140) coherent buffer Data {\n" << " uint value;\n" << "} sb_out;\n"; std::ostringstream main; main << " atomicAdd(sb_out.value, 1u);\n"; // Vertex { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) in vec4 v_in_position;\n" << "\n" << "out " << s_perVertexBlock << ";\n" << "\n" << decl.str() << "\n" << "void main (void)\n" << "{\n" << " gl_Position = v_in_position;\n" << main.str() << "}\n"; programCollection.glslSources.add("read_ib_vert") << glu::VertexSource(src.str()); } // Fragment { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << "void main (void)\n" << "{\n" << " o_color = vec4(1.0);\n" << "}\n"; programCollection.glslSources.add("read_ib_frag") << glu::FragmentSource(src.str()); } // Compute { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(local_size_x = 1) in;\n" << "\n" << decl.str() << "\n" << "void main (void)\n" << "{\n" << main.str() << "}\n"; programCollection.glslSources.add("read_ib_comp") << glu::ComputeSource(src.str()); } } deUint32 getInResourceUsageFlags (void) const { return VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; } deUint32 getOutResourceUsageFlags (void) const { return 0; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return (m_resourceDesc.type == RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT); } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new ReadImplementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; }; class WriteSupport : public OperationSupport { public: WriteSupport (const ResourceDescription& resourceDesc) { DE_ASSERT(isIndirectBuffer(resourceDesc.type)); DE_UNREF(resourceDesc); } deUint32 getInResourceUsageFlags (void) const { return 0; } deUint32 getOutResourceUsageFlags (void) const { return VK_BUFFER_USAGE_TRANSFER_DST_BIT; } VkQueueFlags getQueueFlags (const OperationContext& context) const { DE_UNREF(context); return VK_QUEUE_TRANSFER_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new WriteImplementation(context, resource)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } }; } // IndirectBuffer ns namespace VertexInput { enum DrawMode { DRAW_MODE_VERTEX = 0, DRAW_MODE_INDEXED, }; class Implementation : public Operation { public: Implementation (OperationContext& context, Resource& resource, DrawMode drawMode) : m_context (context) , m_resource (resource) , m_drawMode (drawMode) { requireFeaturesForSSBOAccess (m_context, VK_SHADER_STAGE_VERTEX_BIT); const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); Allocator& allocator = context.getAllocator(); VkFormat attributeFormat = VK_FORMAT_R32G32B32A32_UINT; const VkDeviceSize dataSizeBytes = m_resource.getBuffer().size; // allocate ssbo that will store data used for verification { m_outputBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(dataSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_outputBuffer->getAllocation(); deMemset(alloc.getHostPtr(), 0, static_cast(dataSizeBytes)); flushAlloc(vk, device, alloc); } // allocate buffer that will be used for vertex attributes when we use resource for indices if (m_drawMode == DRAW_MODE_INDEXED) { attributeFormat = VK_FORMAT_R32_UINT; m_inputBuffer = de::MovePtr(new Buffer(vk, device, allocator, makeBufferCreateInfo(dataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible)); const Allocation& alloc = m_inputBuffer->getAllocation(); fillPattern(alloc.getHostPtr(), dataSizeBytes, true); flushAlloc(vk, device, alloc); } m_descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT) .build (vk, device); m_descriptorPool = DescriptorPoolBuilder() .addType (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .build (vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout); const VkDescriptorBufferInfo outputBufferDescriptorInfo = makeDescriptorBufferInfo(m_outputBuffer->get(), 0ull, dataSizeBytes); DescriptorSetUpdateBuilder() .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferDescriptorInfo) .update (vk, device); // Color attachment m_colorFormat = VK_FORMAT_R8G8B8A8_UNORM; m_colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); m_colorImageExtent = makeExtent3D(16u, 16u, 1u); m_colorAttachmentImage = de::MovePtr(new Image(vk, device, allocator, makeImageCreateInfo(VK_IMAGE_TYPE_2D, m_colorImageExtent, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any)); // Pipeline m_colorAttachmentView = makeImageView (vk, device, **m_colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorImageSubresourceRange); m_renderPass = makeRenderPass (vk, device, m_colorFormat); m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, *m_colorAttachmentView, m_colorImageExtent.width, m_colorImageExtent.height); m_pipelineLayout = makePipelineLayout(vk, device, *m_descriptorSetLayout); m_pipeline = GraphicsPipelineBuilder() .setPrimitiveTopology (VK_PRIMITIVE_TOPOLOGY_POINT_LIST) .setRenderSize (tcu::IVec2(static_cast(m_colorImageExtent.width), static_cast(m_colorImageExtent.height))) .setVertexInputSingleAttribute (attributeFormat, tcu::getPixelSize(mapVkFormat(attributeFormat))) .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("input_vert"), DE_NULL) .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("input_frag"), DE_NULL) .build (vk, device, *m_pipelineLayout, *m_renderPass, context.getPipelineCacheData()); } void recordCommands (const VkCommandBuffer cmdBuffer) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDeviceSize dataSizeBytes = m_resource.getBuffer().size; SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_context.getSynchronizationType(), vk, DE_FALSE); // Change color attachment image layout { const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask (VkAccessFlags)0, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR, // VkAccessFlags2KHR dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout **m_colorAttachmentImage, // VkImage image m_colorImageSubresourceRange // VkImageSubresourceRange subresourceRange ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } { const VkRect2D renderArea = makeRect2D(m_colorImageExtent); const tcu::Vec4 clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, clearColor); } vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL); const VkDeviceSize vertexBufferOffset = 0ull; if (m_drawMode == DRAW_MODE_VERTEX) { const deUint32 count = static_cast(dataSizeBytes / sizeof(tcu::UVec4)); vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_resource.getBuffer().handle, &vertexBufferOffset); vk.cmdDraw(cmdBuffer, count, 1u, 0u, 0u); } else // (m_drawMode == DRAW_MODE_INDEXED) { const deUint32 count = static_cast(dataSizeBytes / sizeof(deUint32)); vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &**m_inputBuffer, &vertexBufferOffset); vk.cmdBindIndexBuffer(cmdBuffer, m_resource.getBuffer().handle, 0u, VK_INDEX_TYPE_UINT32); vk.cmdDrawIndexed(cmdBuffer, count, 1, 0, 0, 0); } endRenderPass(vk, cmdBuffer); // Insert a barrier so data written by the shader is available to the host { const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR, // VkPipelineStageFlags2KHR srcStageMask VK_ACCESS_2_SHADER_WRITE_BIT_KHR, // VkAccessFlags2KHR srcAccessMask VK_PIPELINE_STAGE_2_HOST_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask VK_ACCESS_2_HOST_READ_BIT_KHR, // VkAccessFlags2KHR dstAccessMask **m_outputBuffer, // VkBuffer buffer 0u, // VkDeviceSize offset m_resource.getBuffer().size // VkDeviceSize size ); VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); } } SyncInfo getInSyncInfo (void) const { const bool usingIndexedDraw = (m_drawMode == DRAW_MODE_INDEXED); VkPipelineStageFlags2KHR stageMask = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; VkAccessFlags2KHR accessMask = usingIndexedDraw ? VK_ACCESS_2_INDEX_READ_BIT_KHR : VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; if (m_context.getSynchronizationType() == SynchronizationType::SYNCHRONIZATION2) { // test new stages added with VK_KHR_synchronization2 (no need to further duplicate those tests); // with this operation we can test pre_rasterization, index_input and attribute_input flags; // since this operation is executed for three buffers of different size we use diferent flags depending on the size if (m_resource.getBuffer().size > MAX_UPDATE_BUFFER_SIZE) stageMask = VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR; else stageMask = usingIndexedDraw ? VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR : VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR; } const SyncInfo syncInfo = { stageMask, // VkPipelineStageFlags stageMask; accessMask, // VkAccessFlags accessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; }; return syncInfo; } SyncInfo getOutSyncInfo (void) const { return emptySyncInfo; } Data getData (void) const { return getHostBufferData(m_context, *m_outputBuffer, m_resource.getBuffer().size); } void setData (const Data& data) { setHostBufferData(m_context, *m_outputBuffer, data); } private: OperationContext& m_context; Resource& m_resource; DrawMode m_drawMode; de::MovePtr m_inputBuffer; de::MovePtr m_outputBuffer; Move m_renderPass; Move m_framebuffer; Move m_pipelineLayout; Move m_pipeline; VkFormat m_colorFormat; de::MovePtr m_colorAttachmentImage; Move m_colorAttachmentView; VkExtent3D m_colorImageExtent; VkImageSubresourceRange m_colorImageSubresourceRange; Move m_descriptorPool; Move m_descriptorSetLayout; Move m_descriptorSet; }; class Support : public OperationSupport { public: Support(const ResourceDescription& resourceDesc, DrawMode drawMode) : m_resourceDesc (resourceDesc) , m_drawMode (drawMode) { DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_BUFFER || m_resourceDesc.type == RESOURCE_TYPE_INDEX_BUFFER); } void initPrograms (SourceCollections& programCollection) const { // Vertex { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"; if (m_drawMode == DRAW_MODE_VERTEX) { src << "layout(location = 0) in uvec4 v_in_data;\n" << "layout(set = 0, binding = 0, std140) writeonly buffer Output {\n" << " uvec4 data[" << m_resourceDesc.size.x() / sizeof(tcu::UVec4) << "];\n" << "} b_out;\n" << "\n" << "void main (void)\n" << "{\n" << " b_out.data[gl_VertexIndex] = v_in_data;\n" << " gl_PointSize = 1.0f;\n" << "}\n"; } else // DRAW_MODE_INDEXED { src << "layout(location = 0) in uint v_in_data;\n" << "layout(set = 0, binding = 0, std430) writeonly buffer Output {\n" << " uint data[" << m_resourceDesc.size.x() / sizeof(deUint32) << "];\n" << "} b_out;\n" << "\n" << "void main (void)\n" << "{\n" << " b_out.data[gl_VertexIndex] = v_in_data;\n" << " gl_PointSize = 1.0f;\n" << "}\n"; } programCollection.glslSources.add("input_vert") << glu::VertexSource(src.str()); } // Fragment { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" << "\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << "void main (void)\n" << "{\n" << " o_color = vec4(1.0);\n" << "}\n"; programCollection.glslSources.add("input_frag") << glu::FragmentSource(src.str()); } } deUint32 getInResourceUsageFlags (void) const { return (m_drawMode == DRAW_MODE_VERTEX) ? VK_BUFFER_USAGE_VERTEX_BUFFER_BIT : VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } deUint32 getOutResourceUsageFlags (void) const { return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } VkQueueFlags getQueueFlags (const OperationContext&) const { return VK_QUEUE_GRAPHICS_BIT; } de::MovePtr build (OperationContext& context, Resource& resource) const { return de::MovePtr(new Implementation(context, resource, m_drawMode)); } de::MovePtr build (OperationContext&, Resource&, Resource&) const { DE_ASSERT(0); return de::MovePtr(); } private: const ResourceDescription m_resourceDesc; const DrawMode m_drawMode; }; } // VertexInput } // anonymous ns OperationContext::OperationContext (Context& context, SynchronizationType syncType, PipelineCacheData& pipelineCacheData) : m_context (context) , m_syncType (syncType) , m_vki (context.getInstanceInterface()) , m_vk (context.getDeviceInterface()) , m_physicalDevice (context.getPhysicalDevice()) , m_device (context.getDevice()) , m_allocator (context.getDefaultAllocator()) , m_progCollection (context.getBinaryCollection()) , m_pipelineCacheData (pipelineCacheData) { } OperationContext::OperationContext (Context& context, SynchronizationType syncType, const DeviceInterface& vk, const VkDevice device, vk::Allocator& allocator, PipelineCacheData& pipelineCacheData) : m_context (context) , m_syncType (syncType) , m_vki (context.getInstanceInterface()) , m_vk (vk) , m_physicalDevice (context.getPhysicalDevice()) , m_device (device) , m_allocator (allocator) , m_progCollection (context.getBinaryCollection()) , m_pipelineCacheData (pipelineCacheData) { } OperationContext::OperationContext (Context& context, SynchronizationType syncType, const vk::InstanceInterface& vki, const vk::DeviceInterface& vkd, vk::VkPhysicalDevice physicalDevice, vk::VkDevice device, vk::Allocator& allocator, vk::BinaryCollection& programCollection, PipelineCacheData& pipelineCacheData) : m_context (context) , m_syncType (syncType) , m_vki (vki) , m_vk (vkd) , m_physicalDevice (physicalDevice) , m_device (device) , m_allocator (allocator) , m_progCollection (programCollection) , m_pipelineCacheData (pipelineCacheData) { } Resource::Resource (OperationContext& context, const ResourceDescription& desc, const deUint32 usage, const vk::VkSharingMode sharingMode, const std::vector& queueFamilyIndex) : m_type (desc.type) { const DeviceInterface& vk = context.getDeviceInterface(); const InstanceInterface& vki = context.getInstanceInterface(); const VkDevice device = context.getDevice(); const VkPhysicalDevice physDevice = context.getPhysicalDevice(); Allocator& allocator = context.getAllocator(); if (m_type == RESOURCE_TYPE_BUFFER || m_type == RESOURCE_TYPE_INDEX_BUFFER || isIndirectBuffer(m_type)) { m_bufferData.offset = 0u; m_bufferData.size = static_cast(desc.size.x()); VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(m_bufferData.size, usage); bufferCreateInfo.sharingMode = sharingMode; if (queueFamilyIndex.size() > 0) { bufferCreateInfo.queueFamilyIndexCount = static_cast(queueFamilyIndex.size()); bufferCreateInfo.pQueueFamilyIndices = &queueFamilyIndex[0]; } m_buffer = de::MovePtr(new Buffer(vk, device, allocator, bufferCreateInfo, MemoryRequirement::Any)); m_bufferData.handle = **m_buffer; } else if (m_type == RESOURCE_TYPE_IMAGE) { m_imageData.extent = makeExtent3D(desc.size.x(), std::max(1, desc.size.y()), std::max(1, desc.size.z())); m_imageData.imageType = desc.imageType; m_imageData.format = desc.imageFormat; m_imageData.subresourceRange = makeImageSubresourceRange(desc.imageAspect, 0u, 1u, 0u, 1u); m_imageData.subresourceLayers = makeImageSubresourceLayers(desc.imageAspect, 0u, 0u, 1u); VkImageCreateInfo imageInfo = makeImageCreateInfo(m_imageData.imageType, m_imageData.extent, m_imageData.format, usage, desc.imageSamples); imageInfo.sharingMode = sharingMode; if (queueFamilyIndex.size() > 0) { imageInfo.queueFamilyIndexCount = static_cast(queueFamilyIndex.size()); imageInfo.pQueueFamilyIndices = &queueFamilyIndex[0]; } VkImageFormatProperties imageFormatProperties; const VkResult formatResult = vki.getPhysicalDeviceImageFormatProperties(physDevice, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &imageFormatProperties); if (formatResult != VK_SUCCESS) TCU_THROW(NotSupportedError, "Image format is not supported"); if ((imageFormatProperties.sampleCounts & desc.imageSamples) != desc.imageSamples) TCU_THROW(NotSupportedError, "Requested sample count is not supported"); m_image = de::MovePtr(new Image(vk, device, allocator, imageInfo, MemoryRequirement::Any)); m_imageData.handle = **m_image; } else DE_ASSERT(0); } Resource::Resource (ResourceType type, vk::Move buffer, de::MovePtr allocation, vk::VkDeviceSize offset, vk::VkDeviceSize size) : m_type (type) , m_buffer (new Buffer(buffer, allocation)) { DE_ASSERT(type != RESOURCE_TYPE_IMAGE); m_bufferData.handle = m_buffer->get(); m_bufferData.offset = offset; m_bufferData.size = size; } Resource::Resource (vk::Move image, de::MovePtr allocation, const vk::VkExtent3D& extent, vk::VkImageType imageType, vk::VkFormat format, vk::VkImageSubresourceRange subresourceRange, vk::VkImageSubresourceLayers subresourceLayers) : m_type (RESOURCE_TYPE_IMAGE) , m_image (new Image(image, allocation)) { m_imageData.handle = m_image->get(); m_imageData.extent = extent; m_imageData.imageType = imageType; m_imageData.format = format; m_imageData.subresourceRange = subresourceRange; m_imageData.subresourceLayers = subresourceLayers; } vk::VkDeviceMemory Resource::getMemory (void) const { if (m_type == RESOURCE_TYPE_IMAGE) return m_image->getAllocation().getMemory(); else return m_buffer->getAllocation().getMemory(); } //! \note This function exists for performance reasons. We're creating a lot of tests and checking requirements here //! before creating an OperationSupport object is faster. bool isResourceSupported (const OperationName opName, const ResourceDescription& resourceDesc) { switch (opName) { case OPERATION_NAME_WRITE_FILL_BUFFER: case OPERATION_NAME_WRITE_COPY_BUFFER: case OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER: case OPERATION_NAME_WRITE_SSBO_VERTEX: case OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL: case OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION: case OPERATION_NAME_WRITE_SSBO_GEOMETRY: case OPERATION_NAME_WRITE_SSBO_FRAGMENT: case OPERATION_NAME_WRITE_SSBO_COMPUTE: case OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT: case OPERATION_NAME_READ_COPY_BUFFER: case OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE: case OPERATION_NAME_READ_SSBO_VERTEX: case OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL: case OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION: case OPERATION_NAME_READ_SSBO_GEOMETRY: case OPERATION_NAME_READ_SSBO_FRAGMENT: case OPERATION_NAME_READ_SSBO_COMPUTE: case OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT: case OPERATION_NAME_READ_VERTEX_INPUT: return resourceDesc.type == RESOURCE_TYPE_BUFFER; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW: case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW: return resourceDesc.type == RESOURCE_TYPE_INDIRECT_BUFFER_DRAW; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW_INDEXED: case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED: return resourceDesc.type == RESOURCE_TYPE_INDIRECT_BUFFER_DRAW_INDEXED; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DISPATCH: case OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH: return resourceDesc.type == RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH; case OPERATION_NAME_WRITE_UPDATE_INDEX_BUFFER: case OPERATION_NAME_READ_INDEX_INPUT: return resourceDesc.type == RESOURCE_TYPE_INDEX_BUFFER; case OPERATION_NAME_WRITE_UPDATE_BUFFER: return resourceDesc.type == RESOURCE_TYPE_BUFFER && resourceDesc.size.x() <= MAX_UPDATE_BUFFER_SIZE; case OPERATION_NAME_WRITE_COPY_IMAGE: case OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE: case OPERATION_NAME_READ_COPY_IMAGE: case OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_WRITE_CLEAR_ATTACHMENTS: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageType != VK_IMAGE_TYPE_3D && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_WRITE_IMAGE_COMPUTE_MULTISAMPLE: case OPERATION_NAME_READ_RESOLVE_IMAGE: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageAspect == VK_IMAGE_ASPECT_COLOR_BIT && resourceDesc.imageSamples != VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_WRITE_BLIT_IMAGE: case OPERATION_NAME_READ_BLIT_IMAGE: case OPERATION_NAME_WRITE_IMAGE_VERTEX: case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL: case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION: case OPERATION_NAME_WRITE_IMAGE_GEOMETRY: case OPERATION_NAME_WRITE_IMAGE_FRAGMENT: case OPERATION_NAME_WRITE_IMAGE_COMPUTE: case OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT: case OPERATION_NAME_READ_IMAGE_VERTEX: case OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL: case OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION: case OPERATION_NAME_READ_IMAGE_GEOMETRY: case OPERATION_NAME_READ_IMAGE_FRAGMENT: case OPERATION_NAME_READ_IMAGE_COMPUTE: case OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageAspect == VK_IMAGE_ASPECT_COLOR_BIT && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_READ_UBO_VERTEX: case OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL: case OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION: case OPERATION_NAME_READ_UBO_GEOMETRY: case OPERATION_NAME_READ_UBO_FRAGMENT: case OPERATION_NAME_READ_UBO_COMPUTE: case OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT: return resourceDesc.type == RESOURCE_TYPE_BUFFER && resourceDesc.size.x() <= MAX_UBO_RANGE; case OPERATION_NAME_WRITE_CLEAR_COLOR_IMAGE: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageAspect == VK_IMAGE_ASPECT_COLOR_BIT && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_WRITE_CLEAR_DEPTH_STENCIL_IMAGE: return resourceDesc.type == RESOURCE_TYPE_IMAGE && (resourceDesc.imageAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_WRITE_DRAW: case OPERATION_NAME_WRITE_DRAW_INDEXED: case OPERATION_NAME_WRITE_DRAW_INDIRECT: case OPERATION_NAME_WRITE_DRAW_INDEXED_INDIRECT: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageType == VK_IMAGE_TYPE_2D && (resourceDesc.imageAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0 && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; case OPERATION_NAME_COPY_BUFFER: case OPERATION_NAME_COPY_SSBO_VERTEX: case OPERATION_NAME_COPY_SSBO_TESSELLATION_CONTROL: case OPERATION_NAME_COPY_SSBO_TESSELLATION_EVALUATION: case OPERATION_NAME_COPY_SSBO_GEOMETRY: case OPERATION_NAME_COPY_SSBO_FRAGMENT: case OPERATION_NAME_COPY_SSBO_COMPUTE: case OPERATION_NAME_COPY_SSBO_COMPUTE_INDIRECT: return resourceDesc.type == RESOURCE_TYPE_BUFFER; case OPERATION_NAME_COPY_IMAGE: case OPERATION_NAME_BLIT_IMAGE: case OPERATION_NAME_COPY_IMAGE_VERTEX: case OPERATION_NAME_COPY_IMAGE_TESSELLATION_CONTROL: case OPERATION_NAME_COPY_IMAGE_TESSELLATION_EVALUATION: case OPERATION_NAME_COPY_IMAGE_GEOMETRY: case OPERATION_NAME_COPY_IMAGE_FRAGMENT: case OPERATION_NAME_COPY_IMAGE_COMPUTE: case OPERATION_NAME_COPY_IMAGE_COMPUTE_INDIRECT: return resourceDesc.type == RESOURCE_TYPE_IMAGE && resourceDesc.imageAspect == VK_IMAGE_ASPECT_COLOR_BIT && resourceDesc.imageSamples == VK_SAMPLE_COUNT_1_BIT; default: DE_ASSERT(0); return false; } } std::string getOperationName (const OperationName opName) { switch (opName) { case OPERATION_NAME_WRITE_FILL_BUFFER: return "write_fill_buffer"; case OPERATION_NAME_WRITE_UPDATE_BUFFER: return "write_update_buffer"; case OPERATION_NAME_WRITE_COPY_BUFFER: return "write_copy_buffer"; case OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE: return "write_copy_buffer_to_image"; case OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER: return "write_copy_image_to_buffer"; case OPERATION_NAME_WRITE_COPY_IMAGE: return "write_copy_image"; case OPERATION_NAME_WRITE_BLIT_IMAGE: return "write_blit_image"; case OPERATION_NAME_WRITE_SSBO_VERTEX: return "write_ssbo_vertex"; case OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL: return "write_ssbo_tess_control"; case OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION: return "write_ssbo_tess_eval"; case OPERATION_NAME_WRITE_SSBO_GEOMETRY: return "write_ssbo_geometry"; case OPERATION_NAME_WRITE_SSBO_FRAGMENT: return "write_ssbo_fragment"; case OPERATION_NAME_WRITE_SSBO_COMPUTE: return "write_ssbo_compute"; case OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT: return "write_ssbo_compute_indirect"; case OPERATION_NAME_WRITE_IMAGE_VERTEX: return "write_image_vertex"; case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL: return "write_image_tess_control"; case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION: return "write_image_tess_eval"; case OPERATION_NAME_WRITE_IMAGE_GEOMETRY: return "write_image_geometry"; case OPERATION_NAME_WRITE_IMAGE_FRAGMENT: return "write_image_fragment"; case OPERATION_NAME_WRITE_IMAGE_COMPUTE: return "write_image_compute"; case OPERATION_NAME_WRITE_IMAGE_COMPUTE_MULTISAMPLE: return "write_image_compute_multisample"; case OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT: return "write_image_compute_indirect"; case OPERATION_NAME_WRITE_CLEAR_COLOR_IMAGE: return "write_clear_color_image"; case OPERATION_NAME_WRITE_CLEAR_DEPTH_STENCIL_IMAGE: return "write_clear_depth_stencil_image"; case OPERATION_NAME_WRITE_DRAW: return "write_draw"; case OPERATION_NAME_WRITE_DRAW_INDEXED: return "write_draw_indexed"; case OPERATION_NAME_WRITE_DRAW_INDIRECT: return "write_draw_indirect"; case OPERATION_NAME_WRITE_DRAW_INDEXED_INDIRECT: return "write_draw_indexed_indirect"; case OPERATION_NAME_WRITE_CLEAR_ATTACHMENTS: return "write_clear_attachments"; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW: return "write_indirect_buffer_draw"; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW_INDEXED: return "write_indirect_buffer_draw_indexed"; case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DISPATCH: return "write_indirect_buffer_dispatch"; case OPERATION_NAME_WRITE_UPDATE_INDEX_BUFFER: return "write_update_index_buffer"; case OPERATION_NAME_READ_COPY_BUFFER: return "read_copy_buffer"; case OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE: return "read_copy_buffer_to_image"; case OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER: return "read_copy_image_to_buffer"; case OPERATION_NAME_READ_COPY_IMAGE: return "read_copy_image"; case OPERATION_NAME_READ_BLIT_IMAGE: return "read_blit_image"; case OPERATION_NAME_READ_RESOLVE_IMAGE: return "read_resolve_image"; case OPERATION_NAME_READ_UBO_VERTEX: return "read_ubo_vertex"; case OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL: return "read_ubo_tess_control"; case OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION: return "read_ubo_tess_eval"; case OPERATION_NAME_READ_UBO_GEOMETRY: return "read_ubo_geometry"; case OPERATION_NAME_READ_UBO_FRAGMENT: return "read_ubo_fragment"; case OPERATION_NAME_READ_UBO_COMPUTE: return "read_ubo_compute"; case OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT: return "read_ubo_compute_indirect"; case OPERATION_NAME_READ_SSBO_VERTEX: return "read_ssbo_vertex"; case OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL: return "read_ssbo_tess_control"; case OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION: return "read_ssbo_tess_eval"; case OPERATION_NAME_READ_SSBO_GEOMETRY: return "read_ssbo_geometry"; case OPERATION_NAME_READ_SSBO_FRAGMENT: return "read_ssbo_fragment"; case OPERATION_NAME_READ_SSBO_COMPUTE: return "read_ssbo_compute"; case OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT: return "read_ssbo_compute_indirect"; case OPERATION_NAME_READ_IMAGE_VERTEX: return "read_image_vertex"; case OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL: return "read_image_tess_control"; case OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION: return "read_image_tess_eval"; case OPERATION_NAME_READ_IMAGE_GEOMETRY: return "read_image_geometry"; case OPERATION_NAME_READ_IMAGE_FRAGMENT: return "read_image_fragment"; case OPERATION_NAME_READ_IMAGE_COMPUTE: return "read_image_compute"; case OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT: return "read_image_compute_indirect"; case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW: return "read_indirect_buffer_draw"; case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED: return "read_indirect_buffer_draw_indexed"; case OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH: return "read_indirect_buffer_dispatch"; case OPERATION_NAME_READ_VERTEX_INPUT: return "read_vertex_input"; case OPERATION_NAME_READ_INDEX_INPUT: return "read_index_input"; case OPERATION_NAME_COPY_BUFFER: return "copy_buffer"; case OPERATION_NAME_COPY_IMAGE: return "copy_image"; case OPERATION_NAME_BLIT_IMAGE: return "blit_image"; case OPERATION_NAME_COPY_SSBO_VERTEX: return "copy_buffer_vertex"; case OPERATION_NAME_COPY_SSBO_TESSELLATION_CONTROL: return "copy_ssbo_tess_control"; case OPERATION_NAME_COPY_SSBO_TESSELLATION_EVALUATION: return "copy_ssbo_tess_eval"; case OPERATION_NAME_COPY_SSBO_GEOMETRY: return "copy_ssbo_geometry"; case OPERATION_NAME_COPY_SSBO_FRAGMENT: return "copy_ssbo_fragment"; case OPERATION_NAME_COPY_SSBO_COMPUTE: return "copy_ssbo_compute"; case OPERATION_NAME_COPY_SSBO_COMPUTE_INDIRECT: return "copy_ssbo_compute_indirect"; case OPERATION_NAME_COPY_IMAGE_VERTEX: return "copy_image_vertex"; case OPERATION_NAME_COPY_IMAGE_TESSELLATION_CONTROL: return "copy_image_tess_control"; case OPERATION_NAME_COPY_IMAGE_TESSELLATION_EVALUATION: return "copy_image_tess_eval"; case OPERATION_NAME_COPY_IMAGE_GEOMETRY: return "copy_image_geometry"; case OPERATION_NAME_COPY_IMAGE_FRAGMENT: return "copy_image_fragment"; case OPERATION_NAME_COPY_IMAGE_COMPUTE: return "copy_image_compute"; case OPERATION_NAME_COPY_IMAGE_COMPUTE_INDIRECT: return "copy_image_compute_indirect"; default: DE_ASSERT(0); return ""; } } de::MovePtr makeOperationSupport (const OperationName opName, const ResourceDescription& resourceDesc) { switch (opName) { case OPERATION_NAME_WRITE_FILL_BUFFER: return de::MovePtr(new FillUpdateBuffer ::Support (resourceDesc, FillUpdateBuffer::BUFFER_OP_FILL)); case OPERATION_NAME_WRITE_UPDATE_BUFFER: return de::MovePtr(new FillUpdateBuffer ::Support (resourceDesc, FillUpdateBuffer::BUFFER_OP_UPDATE)); case OPERATION_NAME_WRITE_COPY_BUFFER: return de::MovePtr(new CopyBuffer ::Support (resourceDesc, ACCESS_MODE_WRITE)); case OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE: return de::MovePtr(new CopyBufferToImage ::Support (resourceDesc, ACCESS_MODE_WRITE)); case OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER: return de::MovePtr(new CopyImageToBuffer ::Support (resourceDesc, ACCESS_MODE_WRITE)); case OPERATION_NAME_WRITE_COPY_IMAGE: return de::MovePtr(new CopyBlitResolveImage ::Support (resourceDesc, CopyBlitResolveImage::TYPE_COPY, ACCESS_MODE_WRITE)); case OPERATION_NAME_WRITE_BLIT_IMAGE: return de::MovePtr(new CopyBlitResolveImage ::Support (resourceDesc, CopyBlitResolveImage::TYPE_BLIT, ACCESS_MODE_WRITE)); case OPERATION_NAME_WRITE_SSBO_VERTEX: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_WRITE_SSBO_GEOMETRY: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_WRITE_SSBO_FRAGMENT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_WRITE_SSBO_COMPUTE: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_WRITE, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_WRITE_IMAGE_VERTEX: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_WRITE_IMAGE_GEOMETRY: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_WRITE_IMAGE_FRAGMENT: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_WRITE_IMAGE_COMPUTE: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_WRITE, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_WRITE_IMAGE_COMPUTE_MULTISAMPLE: return de::MovePtr(new ShaderAccess ::MSImageSupport(resourceDesc)); case OPERATION_NAME_WRITE_CLEAR_COLOR_IMAGE: return de::MovePtr(new ClearImage ::Support (resourceDesc, ClearImage::CLEAR_MODE_COLOR)); case OPERATION_NAME_WRITE_CLEAR_DEPTH_STENCIL_IMAGE: return de::MovePtr(new ClearImage ::Support (resourceDesc, ClearImage::CLEAR_MODE_DEPTH_STENCIL)); case OPERATION_NAME_WRITE_DRAW: return de::MovePtr(new Draw ::Support (resourceDesc, Draw::DRAW_CALL_DRAW)); case OPERATION_NAME_WRITE_DRAW_INDEXED: return de::MovePtr(new Draw ::Support (resourceDesc, Draw::DRAW_CALL_DRAW_INDEXED)); case OPERATION_NAME_WRITE_DRAW_INDIRECT: return de::MovePtr(new Draw ::Support (resourceDesc, Draw::DRAW_CALL_DRAW_INDIRECT)); case OPERATION_NAME_WRITE_DRAW_INDEXED_INDIRECT: return de::MovePtr(new Draw ::Support (resourceDesc, Draw::DRAW_CALL_DRAW_INDEXED_INDIRECT)); case OPERATION_NAME_WRITE_CLEAR_ATTACHMENTS: return de::MovePtr(new ClearAttachments ::Support (resourceDesc)); case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW: return de::MovePtr(new IndirectBuffer ::WriteSupport (resourceDesc)); case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DRAW_INDEXED: return de::MovePtr(new IndirectBuffer ::WriteSupport (resourceDesc)); case OPERATION_NAME_WRITE_INDIRECT_BUFFER_DISPATCH: return de::MovePtr(new IndirectBuffer ::WriteSupport (resourceDesc)); case OPERATION_NAME_WRITE_UPDATE_INDEX_BUFFER: return de::MovePtr(new FillUpdateBuffer ::Support (resourceDesc, FillUpdateBuffer::BUFFER_OP_UPDATE_WITH_INDEX_PATTERN)); case OPERATION_NAME_READ_COPY_BUFFER: return de::MovePtr(new CopyBuffer ::Support (resourceDesc, ACCESS_MODE_READ)); case OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE: return de::MovePtr(new CopyBufferToImage ::Support (resourceDesc, ACCESS_MODE_READ)); case OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER: return de::MovePtr(new CopyImageToBuffer ::Support (resourceDesc, ACCESS_MODE_READ)); case OPERATION_NAME_READ_COPY_IMAGE: return de::MovePtr(new CopyBlitResolveImage::Support (resourceDesc, CopyBlitResolveImage::TYPE_COPY, ACCESS_MODE_READ)); case OPERATION_NAME_READ_BLIT_IMAGE: return de::MovePtr(new CopyBlitResolveImage::Support (resourceDesc, CopyBlitResolveImage::TYPE_BLIT, ACCESS_MODE_READ)); case OPERATION_NAME_READ_RESOLVE_IMAGE: return de::MovePtr(new CopyBlitResolveImage::Support (resourceDesc, CopyBlitResolveImage::TYPE_RESOLVE, ACCESS_MODE_READ)); case OPERATION_NAME_READ_UBO_VERTEX: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_READ_UBO_GEOMETRY: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_READ_UBO_FRAGMENT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_READ_UBO_COMPUTE: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_UNIFORM, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_READ_SSBO_VERTEX: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_READ_SSBO_GEOMETRY: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_READ_SSBO_FRAGMENT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_READ_SSBO_COMPUTE: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::BufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_READ_IMAGE_VERTEX: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_READ_IMAGE_GEOMETRY: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_READ_IMAGE_FRAGMENT: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_READ_IMAGE_COMPUTE: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::ImageSupport (resourceDesc, ACCESS_MODE_READ, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW: return de::MovePtr(new IndirectBuffer ::ReadSupport (resourceDesc)); case OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED: return de::MovePtr(new IndirectBuffer ::ReadSupport (resourceDesc)); case OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH: return de::MovePtr(new IndirectBuffer ::ReadSupport (resourceDesc)); case OPERATION_NAME_READ_VERTEX_INPUT: return de::MovePtr(new VertexInput ::Support (resourceDesc, VertexInput::DRAW_MODE_VERTEX)); case OPERATION_NAME_READ_INDEX_INPUT: return de::MovePtr(new VertexInput ::Support (resourceDesc, VertexInput::DRAW_MODE_INDEXED)); case OPERATION_NAME_COPY_BUFFER: return de::MovePtr(new CopyBuffer ::CopySupport (resourceDesc)); case OPERATION_NAME_COPY_IMAGE: return de::MovePtr(new CopyBlitResolveImage::CopySupport (resourceDesc, CopyBlitResolveImage::TYPE_COPY)); case OPERATION_NAME_BLIT_IMAGE: return de::MovePtr(new CopyBlitResolveImage::CopySupport (resourceDesc, CopyBlitResolveImage::TYPE_BLIT)); case OPERATION_NAME_COPY_SSBO_VERTEX: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_COPY_SSBO_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_COPY_SSBO_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_COPY_SSBO_GEOMETRY: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_COPY_SSBO_FRAGMENT: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_COPY_SSBO_COMPUTE: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_COPY_SSBO_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::CopyBufferSupport (resourceDesc, BUFFER_TYPE_STORAGE, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); case OPERATION_NAME_COPY_IMAGE_VERTEX: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_VERTEX_BIT)); case OPERATION_NAME_COPY_IMAGE_TESSELLATION_CONTROL: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)); case OPERATION_NAME_COPY_IMAGE_TESSELLATION_EVALUATION: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)); case OPERATION_NAME_COPY_IMAGE_GEOMETRY: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_GEOMETRY_BIT)); case OPERATION_NAME_COPY_IMAGE_FRAGMENT: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_FRAGMENT_BIT)); case OPERATION_NAME_COPY_IMAGE_COMPUTE: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_COMPUTE_BIT)); case OPERATION_NAME_COPY_IMAGE_COMPUTE_INDIRECT: return de::MovePtr(new ShaderAccess ::CopyImageSupport (resourceDesc, VK_SHADER_STAGE_COMPUTE_BIT, ShaderAccess::DISPATCH_CALL_DISPATCH_INDIRECT)); default: DE_ASSERT(0); return de::MovePtr(); } } } // synchronization } // vkt