blob: dd3c845f0bda779b6d52545073a87343264ddbff [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Copyright (c) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Vulkan ShaderRenderCase
*//*--------------------------------------------------------------------*/
#include "vktShaderRender.hpp"
#include "tcuImageCompare.hpp"
#include "tcuImageIO.hpp"
#include "tcuTestLog.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuSurface.hpp"
#include "tcuVector.hpp"
#include "deFilePath.hpp"
#include "deMath.h"
#include "deUniquePtr.hpp"
#include "vkDeviceUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkPlatform.hpp"
#include "vkQueryUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkStrUtil.hpp"
#include "vkTypeUtil.hpp"
#include <vector>
#include <string>
namespace vkt
{
namespace sr
{
using namespace vk;
namespace
{
static const int GRID_SIZE = 64;
static const deUint32 MAX_RENDER_WIDTH = 128;
static const deUint32 MAX_RENDER_HEIGHT = 128;
static const tcu::Vec4 DEFAULT_CLEAR_COLOR = tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f);
static VkImageViewType textureTypeToImageViewType (TextureBinding::Type type)
{
switch (type)
{
case TextureBinding::TYPE_1D: return VK_IMAGE_VIEW_TYPE_1D;
case TextureBinding::TYPE_2D: return VK_IMAGE_VIEW_TYPE_2D;
case TextureBinding::TYPE_3D: return VK_IMAGE_VIEW_TYPE_3D;
case TextureBinding::TYPE_CUBE_MAP: return VK_IMAGE_VIEW_TYPE_CUBE;
case TextureBinding::TYPE_1D_ARRAY: return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
case TextureBinding::TYPE_2D_ARRAY: return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
case TextureBinding::TYPE_CUBE_ARRAY: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
default:
DE_FATAL("Impossible");
return (VkImageViewType)0;
}
}
static VkImageType viewTypeToImageType (VkImageViewType type)
{
switch (type)
{
case VK_IMAGE_VIEW_TYPE_1D:
case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return VK_IMAGE_TYPE_1D;
case VK_IMAGE_VIEW_TYPE_2D:
case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return VK_IMAGE_TYPE_2D;
case VK_IMAGE_VIEW_TYPE_3D: return VK_IMAGE_TYPE_3D;
case VK_IMAGE_VIEW_TYPE_CUBE:
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return VK_IMAGE_TYPE_2D;
default:
DE_FATAL("Impossible");
return (VkImageType)0;
}
}
/*! Gets the next multiple of a given divisor */
static deUint32 getNextMultiple (deUint32 divisor, deUint32 value)
{
if (value % divisor == 0)
{
return value;
}
return value + divisor - (value % divisor);
}
/*! Gets the next value that is multiple of all given divisors */
static deUint32 getNextMultiple (const std::vector<deUint32>& divisors, deUint32 value)
{
deUint32 nextMultiple = value;
bool nextMultipleFound = false;
while (true)
{
nextMultipleFound = true;
for (size_t divNdx = 0; divNdx < divisors.size(); divNdx++)
nextMultipleFound = nextMultipleFound && (nextMultiple % divisors[divNdx] == 0);
if (nextMultipleFound)
break;
DE_ASSERT(nextMultiple < ~((deUint32)0u));
nextMultiple = getNextMultiple(divisors[0], nextMultiple + 1);
}
return nextMultiple;
}
} // anonymous
// QuadGrid.
class QuadGrid
{
public:
QuadGrid (int gridSize,
int screenWidth,
int screenHeight,
const tcu::Vec4& constCoords,
const std::vector<tcu::Mat4>& userAttribTransforms,
const std::vector<TextureBindingSp>& textures);
~QuadGrid (void);
int getGridSize (void) const { return m_gridSize; }
int getNumVertices (void) const { return m_numVertices; }
int getNumTriangles (void) const { return m_numTriangles; }
const tcu::Vec4& getConstCoords (void) const { return m_constCoords; }
const std::vector<tcu::Mat4> getUserAttribTransforms (void) const { return m_userAttribTransforms; }
const std::vector<TextureBindingSp>& getTextures (void) const { return m_textures; }
const tcu::Vec4* getPositions (void) const { return &m_positions[0]; }
const float* getAttribOne (void) const { return &m_attribOne[0]; }
const tcu::Vec4* getCoords (void) const { return &m_coords[0]; }
const tcu::Vec4* getUnitCoords (void) const { return &m_unitCoords[0]; }
const tcu::Vec4* getUserAttrib (int attribNdx) const { return &m_userAttribs[attribNdx][0]; }
const deUint16* getIndices (void) const { return &m_indices[0]; }
tcu::Vec4 getCoords (float sx, float sy) const;
tcu::Vec4 getUnitCoords (float sx, float sy) const;
int getNumUserAttribs (void) const { return (int)m_userAttribTransforms.size(); }
tcu::Vec4 getUserAttrib (int attribNdx, float sx, float sy) const;
private:
const int m_gridSize;
const int m_numVertices;
const int m_numTriangles;
const tcu::Vec4 m_constCoords;
const std::vector<tcu::Mat4> m_userAttribTransforms;
const std::vector<TextureBindingSp>& m_textures;
std::vector<tcu::Vec4> m_screenPos;
std::vector<tcu::Vec4> m_positions;
std::vector<tcu::Vec4> m_coords; //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
std::vector<tcu::Vec4> m_unitCoords; //!< Positive-only coordinates [0.0 .. 1.5].
std::vector<float> m_attribOne;
std::vector<tcu::Vec4> m_userAttribs[ShaderEvalContext::MAX_TEXTURES];
std::vector<deUint16> m_indices;
};
QuadGrid::QuadGrid (int gridSize,
int width,
int height,
const tcu::Vec4& constCoords,
const std::vector<tcu::Mat4>& userAttribTransforms,
const std::vector<TextureBindingSp>& textures)
: m_gridSize (gridSize)
, m_numVertices ((gridSize + 1) * (gridSize + 1))
, m_numTriangles (gridSize * gridSize * 2)
, m_constCoords (constCoords)
, m_userAttribTransforms (userAttribTransforms)
, m_textures (textures)
{
const tcu::Vec4 viewportScale ((float)width, (float)height, 0.0f, 0.0f);
// Compute vertices.
m_screenPos.resize(m_numVertices);
m_positions.resize(m_numVertices);
m_coords.resize(m_numVertices);
m_unitCoords.resize(m_numVertices);
m_attribOne.resize(m_numVertices);
// User attributes.
for (int attrNdx = 0; attrNdx < DE_LENGTH_OF_ARRAY(m_userAttribs); attrNdx++)
m_userAttribs[attrNdx].resize(m_numVertices);
for (int y = 0; y < gridSize+1; y++)
for (int x = 0; x < gridSize+1; x++)
{
float sx = (float)x / (float)gridSize;
float sy = (float)y / (float)gridSize;
float fx = 2.0f * sx - 1.0f;
float fy = 2.0f * sy - 1.0f;
int vtxNdx = ((y * (gridSize+1)) + x);
m_positions[vtxNdx] = tcu::Vec4(fx, fy, 0.0f, 1.0f);
m_coords[vtxNdx] = getCoords(sx, sy);
m_unitCoords[vtxNdx] = getUnitCoords(sx, sy);
m_attribOne[vtxNdx] = 1.0f;
m_screenPos[vtxNdx] = tcu::Vec4(sx, sy, 0.0f, 1.0f) * viewportScale;
for (int attribNdx = 0; attribNdx < getNumUserAttribs(); attribNdx++)
m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
}
// Compute indices.
m_indices.resize(3 * m_numTriangles);
for (int y = 0; y < gridSize; y++)
for (int x = 0; x < gridSize; x++)
{
int stride = gridSize + 1;
int v00 = (y * stride) + x;
int v01 = (y * stride) + x + 1;
int v10 = ((y+1) * stride) + x;
int v11 = ((y+1) * stride) + x + 1;
int baseNdx = ((y * gridSize) + x) * 6;
m_indices[baseNdx + 0] = (deUint16)v10;
m_indices[baseNdx + 1] = (deUint16)v00;
m_indices[baseNdx + 2] = (deUint16)v01;
m_indices[baseNdx + 3] = (deUint16)v10;
m_indices[baseNdx + 4] = (deUint16)v01;
m_indices[baseNdx + 5] = (deUint16)v11;
}
}
QuadGrid::~QuadGrid (void)
{
}
inline tcu::Vec4 QuadGrid::getCoords (float sx, float sy) const
{
const float fx = 2.0f * sx - 1.0f;
const float fy = 2.0f * sy - 1.0f;
return tcu::Vec4(fx, fy, -fx + 0.33f*fy, -0.275f*fx - fy);
}
inline tcu::Vec4 QuadGrid::getUnitCoords (float sx, float sy) const
{
return tcu::Vec4(sx, sy, 0.33f*sx + 0.5f*sy, 0.5f*sx + 0.25f*sy);
}
inline tcu::Vec4 QuadGrid::getUserAttrib (int attribNdx, float sx, float sy) const
{
// homogeneous normalized screen-space coordinates
return m_userAttribTransforms[attribNdx] * tcu::Vec4(sx, sy, 0.0f, 1.0f);
}
// TextureBinding
TextureBinding::TextureBinding (const tcu::Archive& archive,
const char* filename,
const Type type,
const tcu::Sampler& sampler)
: m_type (type)
, m_sampler (sampler)
{
switch(m_type)
{
case TYPE_2D: m_binding.tex2D = loadTexture2D(archive, filename).release(); break;
default:
DE_FATAL("Unsupported texture type");
}
}
TextureBinding::TextureBinding (const tcu::Texture1D* tex1D, const tcu::Sampler& sampler)
: m_type (TYPE_1D)
, m_sampler (sampler)
{
m_binding.tex1D = tex1D;
}
TextureBinding::TextureBinding (const tcu::Texture2D* tex2D, const tcu::Sampler& sampler)
: m_type (TYPE_2D)
, m_sampler (sampler)
{
m_binding.tex2D = tex2D;
}
TextureBinding::TextureBinding (const tcu::Texture3D* tex3D, const tcu::Sampler& sampler)
: m_type (TYPE_3D)
, m_sampler (sampler)
{
m_binding.tex3D = tex3D;
}
TextureBinding::TextureBinding (const tcu::TextureCube* texCube, const tcu::Sampler& sampler)
: m_type (TYPE_CUBE_MAP)
, m_sampler (sampler)
{
m_binding.texCube = texCube;
}
TextureBinding::TextureBinding (const tcu::Texture1DArray* tex1DArray, const tcu::Sampler& sampler)
: m_type (TYPE_1D_ARRAY)
, m_sampler (sampler)
{
m_binding.tex1DArray = tex1DArray;
}
TextureBinding::TextureBinding (const tcu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler)
: m_type (TYPE_2D_ARRAY)
, m_sampler (sampler)
{
m_binding.tex2DArray = tex2DArray;
}
TextureBinding::TextureBinding (const tcu::TextureCubeArray* texCubeArray, const tcu::Sampler& sampler)
: m_type (TYPE_CUBE_ARRAY)
, m_sampler (sampler)
{
m_binding.texCubeArray = texCubeArray;
}
TextureBinding::~TextureBinding (void)
{
switch(m_type)
{
case TYPE_1D: delete m_binding.tex1D; break;
case TYPE_2D: delete m_binding.tex2D; break;
case TYPE_3D: delete m_binding.tex3D; break;
case TYPE_CUBE_MAP: delete m_binding.texCube; break;
case TYPE_1D_ARRAY: delete m_binding.tex1DArray; break;
case TYPE_2D_ARRAY: delete m_binding.tex2DArray; break;
case TYPE_CUBE_ARRAY: delete m_binding.texCubeArray; break;
default: break;
}
}
de::MovePtr<tcu::Texture2D> TextureBinding::loadTexture2D (const tcu::Archive& archive, const char* filename)
{
tcu::TextureLevel level;
tcu::ImageIO::loadImage(level, archive, filename);
TCU_CHECK_INTERNAL(level.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) ||
level.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8));
// \todo [2015-10-08 elecro] for some reason we get better when using RGBA texture even in RGB case, this needs to be investigated
de::MovePtr<tcu::Texture2D> texture(new tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), level.getWidth(), level.getHeight()));
// Fill level 0.
texture->allocLevel(0);
tcu::copy(texture->getLevel(0), level.getAccess());
return texture;
}
// ShaderEvalContext.
ShaderEvalContext::ShaderEvalContext (const QuadGrid& quadGrid)
: constCoords (quadGrid.getConstCoords())
, isDiscarded (false)
, m_quadGrid (quadGrid)
{
const std::vector<TextureBindingSp>& bindings = m_quadGrid.getTextures();
DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
// Fill in texture array.
for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
{
const TextureBinding& binding = *bindings[ndx];
if (binding.getType() == TextureBinding::TYPE_NONE)
continue;
textures[ndx].sampler = binding.getSampler();
switch (binding.getType())
{
case TextureBinding::TYPE_1D: textures[ndx].tex1D = &binding.get1D(); break;
case TextureBinding::TYPE_2D: textures[ndx].tex2D = &binding.get2D(); break;
case TextureBinding::TYPE_3D: textures[ndx].tex3D = &binding.get3D(); break;
case TextureBinding::TYPE_CUBE_MAP: textures[ndx].texCube = &binding.getCube(); break;
case TextureBinding::TYPE_1D_ARRAY: textures[ndx].tex1DArray = &binding.get1DArray(); break;
case TextureBinding::TYPE_2D_ARRAY: textures[ndx].tex2DArray = &binding.get2DArray(); break;
case TextureBinding::TYPE_CUBE_ARRAY: textures[ndx].texCubeArray = &binding.getCubeArray(); break;
default:
TCU_THROW(InternalError, "Handling of texture binding type not implemented");
}
}
}
ShaderEvalContext::~ShaderEvalContext (void)
{
}
void ShaderEvalContext::reset (float sx, float sy)
{
// Clear old values
color = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
isDiscarded = false;
// Compute coords
coords = m_quadGrid.getCoords(sx, sy);
unitCoords = m_quadGrid.getUnitCoords(sx, sy);
// Compute user attributes.
const int numAttribs = m_quadGrid.getNumUserAttribs();
DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS);
for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++)
in[attribNdx] = m_quadGrid.getUserAttrib(attribNdx, sx, sy);
}
tcu::Vec4 ShaderEvalContext::texture2D (int unitNdx, const tcu::Vec2& texCoords)
{
if (textures[unitNdx].tex2D)
return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f);
else
return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
}
// ShaderEvaluator.
ShaderEvaluator::ShaderEvaluator (void)
: m_evalFunc(DE_NULL)
{
}
ShaderEvaluator::ShaderEvaluator (ShaderEvalFunc evalFunc)
: m_evalFunc(evalFunc)
{
}
ShaderEvaluator::~ShaderEvaluator (void)
{
}
void ShaderEvaluator::evaluate (ShaderEvalContext& ctx) const
{
DE_ASSERT(m_evalFunc);
m_evalFunc(ctx);
}
// UniformSetup.
UniformSetup::UniformSetup (void)
: m_setupFunc(DE_NULL)
{
}
UniformSetup::UniformSetup (UniformSetupFunc setupFunc)
: m_setupFunc(setupFunc)
{
}
UniformSetup::~UniformSetup (void)
{
}
void UniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
{
if (m_setupFunc)
m_setupFunc(instance, constCoords);
}
// ShaderRenderCase.
ShaderRenderCase::ShaderRenderCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const bool isVertexCase,
const ShaderEvalFunc evalFunc,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc)
: vkt::TestCase (testCtx, name, description)
, m_isVertexCase (isVertexCase)
, m_evaluator (new ShaderEvaluator(evalFunc))
, m_uniformSetup (uniformSetup ? uniformSetup : new UniformSetup())
, m_attribFunc (attribFunc)
{}
ShaderRenderCase::ShaderRenderCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const bool isVertexCase,
const ShaderEvaluator* evaluator,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc)
: vkt::TestCase (testCtx, name, description)
, m_isVertexCase (isVertexCase)
, m_evaluator (evaluator)
, m_uniformSetup (uniformSetup ? uniformSetup : new UniformSetup())
, m_attribFunc (attribFunc)
{}
ShaderRenderCase::~ShaderRenderCase (void)
{
}
void ShaderRenderCase::initPrograms (vk::SourceCollections& programCollection) const
{
programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
}
TestInstance* ShaderRenderCase::createInstance (Context& context) const
{
DE_ASSERT(m_evaluator != DE_NULL);
DE_ASSERT(m_uniformSetup != DE_NULL);
return new ShaderRenderCaseInstance(context, m_isVertexCase, *m_evaluator, *m_uniformSetup, m_attribFunc);
}
// ShaderRenderCaseInstance.
ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context& context)
: vkt::TestInstance (context)
, m_imageBackingMode (IMAGE_BACKING_MODE_REGULAR)
, m_sparseContext (createSparseContext())
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (false)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (128, 128)
, m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
, m_evaluator (DE_NULL)
, m_uniformSetup (DE_NULL)
, m_attribFunc (DE_NULL)
, m_sampleCount (VK_SAMPLE_COUNT_1_BIT)
{
}
ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context& context,
const bool isVertexCase,
const ShaderEvaluator& evaluator,
const UniformSetup& uniformSetup,
const AttributeSetupFunc attribFunc,
const ImageBackingMode imageBackingMode)
: vkt::TestInstance (context)
, m_imageBackingMode (imageBackingMode)
, m_sparseContext (createSparseContext())
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (isVertexCase)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (128, 128)
, m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
, m_evaluator (&evaluator)
, m_uniformSetup (&uniformSetup)
, m_attribFunc (attribFunc)
, m_sampleCount (VK_SAMPLE_COUNT_1_BIT)
{
}
ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context& context,
const bool isVertexCase,
const ShaderEvaluator* evaluator,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc,
const ImageBackingMode imageBackingMode)
: vkt::TestInstance (context)
, m_imageBackingMode (imageBackingMode)
, m_sparseContext (createSparseContext())
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (isVertexCase)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (128, 128)
, m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
, m_evaluator (evaluator)
, m_uniformSetup (uniformSetup)
, m_attribFunc (attribFunc)
, m_sampleCount (VK_SAMPLE_COUNT_1_BIT)
{
}
static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
{
const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
{
if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
return (deUint32)queueNdx;
}
TCU_THROW(NotSupportedError, "No matching queue found");
}
ShaderRenderCaseInstance::SparseContext::SparseContext (vkt::Context& context)
: m_context (context)
, m_queueFamilyIndex (findQueueFamilyIndexWithCaps(context.getInstanceInterface(), context.getPhysicalDevice(), VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT))
, m_device (createDevice())
, m_deviceInterface (context.getInstanceInterface(), *m_device)
, m_allocator (createAllocator())
{
m_deviceInterface.getDeviceQueue(*m_device, m_queueFamilyIndex, 0, &m_queue);
}
Move<VkDevice> ShaderRenderCaseInstance::SparseContext::createDevice () const
{
const InstanceInterface& vk = m_context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
VkDeviceQueueCreateInfo queueInfo;
VkDeviceCreateInfo deviceInfo;
const float queuePriority = 1.0f;
deMemset(&queueInfo, 0, sizeof(queueInfo));
deMemset(&deviceInfo, 0, sizeof(deviceInfo));
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo.pNext = DE_NULL;
queueInfo.flags = (VkDeviceQueueCreateFlags)0u;
queueInfo.queueFamilyIndex = m_queueFamilyIndex;
queueInfo.queueCount = 1u;
queueInfo.pQueuePriorities = &queuePriority;
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceInfo.pNext = DE_NULL;
deviceInfo.queueCreateInfoCount = 1u;
deviceInfo.pQueueCreateInfos = &queueInfo;
deviceInfo.enabledExtensionCount = 0u;
deviceInfo.ppEnabledExtensionNames = DE_NULL;
deviceInfo.enabledLayerCount = 0u;
deviceInfo.ppEnabledLayerNames = DE_NULL;
deviceInfo.pEnabledFeatures = &deviceFeatures;
return vk::createDevice(vk, physicalDevice, &deviceInfo);
}
vk::Allocator* ShaderRenderCaseInstance::SparseContext::createAllocator () const
{
const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice());
return new SimpleAllocator(m_deviceInterface, *m_device, memoryProperties);
}
ShaderRenderCaseInstance::SparseContext* ShaderRenderCaseInstance::createSparseContext (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
{
return new SparseContext(m_context);
}
return DE_NULL;
}
vk::Allocator& ShaderRenderCaseInstance::getAllocator (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
{
return *m_sparseContext->m_allocator;
}
return m_context.getDefaultAllocator();
}
ShaderRenderCaseInstance::~ShaderRenderCaseInstance (void)
{
}
VkDevice ShaderRenderCaseInstance::getDevice (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
return *m_sparseContext->m_device;
return m_context.getDevice();
}
deUint32 ShaderRenderCaseInstance::getUniversalQueueFamilyIndex (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
return m_sparseContext->m_queueFamilyIndex;
return m_context.getUniversalQueueFamilyIndex();
}
const DeviceInterface& ShaderRenderCaseInstance::getDeviceInterface (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
return m_sparseContext->m_deviceInterface;
return m_context.getDeviceInterface();
}
VkQueue ShaderRenderCaseInstance::getUniversalQueue (void) const
{
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
return m_sparseContext->m_queue;
return m_context.getUniversalQueue();
}
VkPhysicalDevice ShaderRenderCaseInstance::getPhysicalDevice (void) const
{
// Same in sparse and regular case
return m_context.getPhysicalDevice();
}
const InstanceInterface& ShaderRenderCaseInstance::getInstanceInterface (void) const
{
// Same in sparse and regular case
return m_context.getInstanceInterface();
}
tcu::TestStatus ShaderRenderCaseInstance::iterate (void)
{
setup();
// Create quad grid.
const tcu::UVec2 viewportSize = getViewportSize();
const int width = viewportSize.x();
const int height = viewportSize.y();
m_quadGrid = de::MovePtr<QuadGrid>(new QuadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, getDefaultConstCoords(), m_userAttribTransforms, m_textures));
// Render result.
tcu::Surface resImage (width, height);
render(m_quadGrid->getNumVertices(), m_quadGrid->getNumTriangles(), m_quadGrid->getIndices(), m_quadGrid->getConstCoords());
tcu::copy(resImage.getAccess(), m_resultImage.getAccess());
// Compute reference.
tcu::Surface refImage (width, height);
if (m_isVertexCase)
computeVertexReference(refImage, *m_quadGrid);
else
computeFragmentReference(refImage, *m_quadGrid);
// Compare.
const bool compareOk = compareImages(resImage, refImage, 0.1f);
if (compareOk)
return tcu::TestStatus::pass("Result image matches reference");
else
return tcu::TestStatus::fail("Image mismatch");
}
void ShaderRenderCaseInstance::setup (void)
{
m_resultImage = tcu::TextureLevel();
m_descriptorSetLayoutBuilder = de::MovePtr<DescriptorSetLayoutBuilder> (new DescriptorSetLayoutBuilder());
m_descriptorPoolBuilder = de::MovePtr<DescriptorPoolBuilder> (new DescriptorPoolBuilder());
m_descriptorSetUpdateBuilder = de::MovePtr<DescriptorSetUpdateBuilder> (new DescriptorSetUpdateBuilder());
m_uniformInfos.clear();
m_vertexBindingDescription.clear();
m_vertexAttributeDescription.clear();
m_vertexBuffers.clear();
m_vertexBufferAllocs.clear();
m_pushConstantRanges.clear();
}
void ShaderRenderCaseInstance::setupUniformData (deUint32 bindingLocation, size_t size, const void* dataPtr)
{
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const VkBufferCreateInfo uniformBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
size, // VkDeviceSize size;
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &uniformBufferParams);
de::MovePtr<Allocation> alloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset()));
deMemcpy(alloc->getHostPtr(), dataPtr, size);
flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), size);
de::MovePtr<BufferUniform> uniformInfo(new BufferUniform());
uniformInfo->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size);
uniformInfo->location = bindingLocation;
uniformInfo->buffer = VkBufferSp(new vk::Unique<VkBuffer>(buffer));
uniformInfo->alloc = AllocationSp(alloc.release());
m_uniformInfos.push_back(UniformInfoSp(new de::UniquePtr<UniformInfo>(uniformInfo)));
}
void ShaderRenderCaseInstance::addUniform (deUint32 bindingLocation, vk::VkDescriptorType descriptorType, size_t dataSize, const void* data)
{
m_descriptorSetLayoutBuilder->addSingleBinding(descriptorType, vk::VK_SHADER_STAGE_ALL);
m_descriptorPoolBuilder->addType(descriptorType);
setupUniformData(bindingLocation, dataSize, data);
}
void ShaderRenderCaseInstance::addAttribute (deUint32 bindingLocation,
vk::VkFormat format,
deUint32 sizePerElement,
deUint32 count,
const void* dataPtr)
{
// Add binding specification
const deUint32 binding = (deUint32)m_vertexBindingDescription.size();
const VkVertexInputBindingDescription bindingDescription =
{
binding, // deUint32 binding;
sizePerElement, // deUint32 stride;
VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate stepRate;
};
m_vertexBindingDescription.push_back(bindingDescription);
// Add location and format specification
const VkVertexInputAttributeDescription attributeDescription =
{
bindingLocation, // deUint32 location;
binding, // deUint32 binding;
format, // VkFormat format;
0u, // deUint32 offset;
};
m_vertexAttributeDescription.push_back(attributeDescription);
// Upload data to buffer
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const VkDeviceSize inputSize = sizePerElement * count;
const VkBufferCreateInfo vertexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
inputSize, // VkDeviceSize size;
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &vertexBufferParams);
de::MovePtr<vk::Allocation> alloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset()));
deMemcpy(alloc->getHostPtr(), dataPtr, (size_t)inputSize);
flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), inputSize);
m_vertexBuffers.push_back(VkBufferSp(new vk::Unique<VkBuffer>(buffer)));
m_vertexBufferAllocs.push_back(AllocationSp(alloc.release()));
}
void ShaderRenderCaseInstance::useAttribute (deUint32 bindingLocation, BaseAttributeType type)
{
const EnabledBaseAttribute attribute =
{
bindingLocation, // deUint32 location;
type // BaseAttributeType type;
};
m_enabledBaseAttributes.push_back(attribute);
}
void ShaderRenderCaseInstance::setupUniforms (const tcu::Vec4& constCoords)
{
if (m_uniformSetup)
m_uniformSetup->setup(*this, constCoords);
}
void ShaderRenderCaseInstance::useUniform (deUint32 bindingLocation, BaseUniformType type)
{
#define UNIFORM_CASE(type, value) case type: addUniform(bindingLocation, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, value); break
switch(type)
{
// Bool
UNIFORM_CASE(UB_FALSE, 0);
UNIFORM_CASE(UB_TRUE, 1);
// BVec4
UNIFORM_CASE(UB4_FALSE, tcu::Vec4(0));
UNIFORM_CASE(UB4_TRUE, tcu::Vec4(1));
// Integer
UNIFORM_CASE(UI_ZERO, 0);
UNIFORM_CASE(UI_ONE, 1);
UNIFORM_CASE(UI_TWO, 2);
UNIFORM_CASE(UI_THREE, 3);
UNIFORM_CASE(UI_FOUR, 4);
UNIFORM_CASE(UI_FIVE, 5);
UNIFORM_CASE(UI_SIX, 6);
UNIFORM_CASE(UI_SEVEN, 7);
UNIFORM_CASE(UI_EIGHT, 8);
UNIFORM_CASE(UI_ONEHUNDREDONE, 101);
// IVec2
UNIFORM_CASE(UI2_MINUS_ONE, tcu::IVec2(-1));
UNIFORM_CASE(UI2_ZERO, tcu::IVec2(0));
UNIFORM_CASE(UI2_ONE, tcu::IVec2(1));
UNIFORM_CASE(UI2_TWO, tcu::IVec2(2));
UNIFORM_CASE(UI2_THREE, tcu::IVec2(3));
UNIFORM_CASE(UI2_FOUR, tcu::IVec2(4));
UNIFORM_CASE(UI2_FIVE, tcu::IVec2(5));
// IVec3
UNIFORM_CASE(UI3_MINUS_ONE, tcu::IVec3(-1));
UNIFORM_CASE(UI3_ZERO, tcu::IVec3(0));
UNIFORM_CASE(UI3_ONE, tcu::IVec3(1));
UNIFORM_CASE(UI3_TWO, tcu::IVec3(2));
UNIFORM_CASE(UI3_THREE, tcu::IVec3(3));
UNIFORM_CASE(UI3_FOUR, tcu::IVec3(4));
UNIFORM_CASE(UI3_FIVE, tcu::IVec3(5));
// IVec4
UNIFORM_CASE(UI4_MINUS_ONE, tcu::IVec4(-1));
UNIFORM_CASE(UI4_ZERO, tcu::IVec4(0));
UNIFORM_CASE(UI4_ONE, tcu::IVec4(1));
UNIFORM_CASE(UI4_TWO, tcu::IVec4(2));
UNIFORM_CASE(UI4_THREE, tcu::IVec4(3));
UNIFORM_CASE(UI4_FOUR, tcu::IVec4(4));
UNIFORM_CASE(UI4_FIVE, tcu::IVec4(5));
// Float
UNIFORM_CASE(UF_ZERO, 0.0f);
UNIFORM_CASE(UF_ONE, 1.0f);
UNIFORM_CASE(UF_TWO, 2.0f);
UNIFORM_CASE(UF_THREE, 3.0f);
UNIFORM_CASE(UF_FOUR, 4.0f);
UNIFORM_CASE(UF_FIVE, 5.0f);
UNIFORM_CASE(UF_SIX, 6.0f);
UNIFORM_CASE(UF_SEVEN, 7.0f);
UNIFORM_CASE(UF_EIGHT, 8.0f);
UNIFORM_CASE(UF_HALF, 1.0f / 2.0f);
UNIFORM_CASE(UF_THIRD, 1.0f / 3.0f);
UNIFORM_CASE(UF_FOURTH, 1.0f / 4.0f);
UNIFORM_CASE(UF_FIFTH, 1.0f / 5.0f);
UNIFORM_CASE(UF_SIXTH, 1.0f / 6.0f);
UNIFORM_CASE(UF_SEVENTH, 1.0f / 7.0f);
UNIFORM_CASE(UF_EIGHTH, 1.0f / 8.0f);
// Vec2
UNIFORM_CASE(UV2_MINUS_ONE, tcu::Vec2(-1.0f));
UNIFORM_CASE(UV2_ZERO, tcu::Vec2(0.0f));
UNIFORM_CASE(UV2_ONE, tcu::Vec2(1.0f));
UNIFORM_CASE(UV2_TWO, tcu::Vec2(2.0f));
UNIFORM_CASE(UV2_THREE, tcu::Vec2(3.0f));
UNIFORM_CASE(UV2_HALF, tcu::Vec2(1.0f / 2.0f));
// Vec3
UNIFORM_CASE(UV3_MINUS_ONE, tcu::Vec3(-1.0f));
UNIFORM_CASE(UV3_ZERO, tcu::Vec3(0.0f));
UNIFORM_CASE(UV3_ONE, tcu::Vec3(1.0f));
UNIFORM_CASE(UV3_TWO, tcu::Vec3(2.0f));
UNIFORM_CASE(UV3_THREE, tcu::Vec3(3.0f));
UNIFORM_CASE(UV3_HALF, tcu::Vec3(1.0f / 2.0f));
// Vec4
UNIFORM_CASE(UV4_MINUS_ONE, tcu::Vec4(-1.0f));
UNIFORM_CASE(UV4_ZERO, tcu::Vec4(0.0f));
UNIFORM_CASE(UV4_ONE, tcu::Vec4(1.0f));
UNIFORM_CASE(UV4_TWO, tcu::Vec4(2.0f));
UNIFORM_CASE(UV4_THREE, tcu::Vec4(3.0f));
UNIFORM_CASE(UV4_HALF, tcu::Vec4(1.0f / 2.0f));
UNIFORM_CASE(UV4_BLACK, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
UNIFORM_CASE(UV4_GRAY, tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
UNIFORM_CASE(UV4_WHITE, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
default:
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Unknown Uniform type: " << type << tcu::TestLog::EndMessage;
break;
}
#undef UNIFORM_CASE
}
const tcu::UVec2 ShaderRenderCaseInstance::getViewportSize (void) const
{
return tcu::UVec2(de::min(m_renderSize.x(), MAX_RENDER_WIDTH),
de::min(m_renderSize.y(), MAX_RENDER_HEIGHT));
}
void ShaderRenderCaseInstance::setSampleCount (VkSampleCountFlagBits sampleCount)
{
m_sampleCount = sampleCount;
}
bool ShaderRenderCaseInstance::isMultiSampling (void) const
{
return m_sampleCount != VK_SAMPLE_COUNT_1_BIT;
}
void ShaderRenderCaseInstance::uploadImage (const tcu::TextureFormat& texFormat,
const TextureData& textureData,
const tcu::Sampler& refSampler,
deUint32 mipLevels,
deUint32 arrayLayers,
VkImage destImage)
{
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const VkQueue queue = getUniversalQueue();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const bool isShadowSampler = refSampler.compare != tcu::Sampler::COMPAREMODE_NONE;
const VkImageAspectFlags aspectMask = isShadowSampler ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
deUint32 bufferSize = 0u;
Move<VkBuffer> buffer;
de::MovePtr<Allocation> bufferAlloc;
Move<VkCommandPool> cmdPool;
Move<VkCommandBuffer> cmdBuffer;
Move<VkFence> fence;
std::vector<VkBufferImageCopy> copyRegions;
std::vector<deUint32> offsetMultiples;
offsetMultiples.push_back(4u);
offsetMultiples.push_back(texFormat.getPixelSize());
// Calculate buffer size
for (TextureData::const_iterator mit = textureData.begin(); mit != textureData.end(); ++mit)
{
for (TextureLayerData::const_iterator lit = mit->begin(); lit != mit->end(); ++lit)
{
const tcu::ConstPixelBufferAccess& access = *lit;
bufferSize = getNextMultiple(offsetMultiples, bufferSize);
bufferSize += access.getWidth() * access.getHeight() * access.getDepth() * access.getFormat().getPixelSize();
}
}
// Create source buffer
{
const VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
0u, // deUint32 queueFamilyIndexCount;
DE_NULL, // const deUint32* pQueueFamilyIndices;
};
buffer = createBuffer(vk, vkDevice, &bufferParams);
bufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
}
// Create command pool and buffer
{
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCommandPool commandPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
1u, // deUint32 bufferCount;
};
cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
}
// Create fence
{
const VkFenceCreateInfo fenceParams =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u // VkFenceCreateFlags flags;
};
fence = createFence(vk, vkDevice, &fenceParams);
}
// Barriers for copying buffer to image
const VkBufferMemoryBarrier preBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*buffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
bufferSize // VkDeviceSize size;
};
const VkImageMemoryBarrier preImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
destImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkImageMemoryBarrier postImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
destImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
// Get copy regions and write buffer data
{
deUint32 layerDataOffset = 0;
deUint8* destPtr = (deUint8*)bufferAlloc->getHostPtr();
for (size_t levelNdx = 0; levelNdx < textureData.size(); levelNdx++)
{
const TextureLayerData& layerData = textureData[levelNdx];
for (size_t layerNdx = 0; layerNdx < layerData.size(); layerNdx++)
{
layerDataOffset = getNextMultiple(offsetMultiples, layerDataOffset);
const tcu::ConstPixelBufferAccess& access = layerData[layerNdx];
const tcu::PixelBufferAccess destAccess (access.getFormat(), access.getSize(), destPtr + layerDataOffset);
const VkBufferImageCopy layerRegion =
{
layerDataOffset, // VkDeviceSize bufferOffset;
(deUint32)access.getWidth(), // deUint32 bufferRowLength;
(deUint32)access.getHeight(), // deUint32 bufferImageHeight;
{ // VkImageSubresourceLayers imageSubresource;
aspectMask, // VkImageAspectFlags aspectMask;
(deUint32)levelNdx, // uint32_t mipLevel;
(deUint32)layerNdx, // uint32_t baseArrayLayer;
1u // uint32_t layerCount;
},
{ 0u, 0u, 0u }, // VkOffset3D imageOffset;
{ // VkExtent3D imageExtent;
(deUint32)access.getWidth(),
(deUint32)access.getHeight(),
(deUint32)access.getDepth()
}
};
copyRegions.push_back(layerRegion);
tcu::copy(destAccess, access);
layerDataOffset += access.getWidth() * access.getHeight() * access.getDepth() * access.getFormat().getPixelSize();
}
}
}
flushMappedMemoryRange(vk, vkDevice, bufferAlloc->getMemory(), bufferAlloc->getOffset(), bufferSize);
// Copy buffer to image
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &preBufferBarrier, 1, &preImageBarrier);
vk.cmdCopyBufferToImage(*cmdBuffer, *buffer, destImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)copyRegions.size(), copyRegions.data());
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // deUint32 waitSemaphoreCount;
DE_NULL, // const VkSemaphore* pWaitSemaphores;
DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
1u, // deUint32 commandBufferCount;
&cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
0u, // deUint32 signalSemaphoreCount;
DE_NULL // const VkSemaphore* pSignalSemaphores;
};
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */));
}
void ShaderRenderCaseInstance::clearImage (const tcu::Sampler& refSampler,
deUint32 mipLevels,
deUint32 arrayLayers,
VkImage destImage)
{
const VkDevice vkDevice = m_context.getDevice();
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const bool isShadowSampler = refSampler.compare != tcu::Sampler::COMPAREMODE_NONE;
const VkImageAspectFlags aspectMask = isShadowSampler ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
Move<VkCommandPool> cmdPool;
Move<VkCommandBuffer> cmdBuffer;
Move<VkFence> fence;
VkClearValue clearValue;
deMemset(&clearValue, 0, sizeof(clearValue));
// Create command pool and buffer
{
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCommandPool commandPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
1u, // deUint32 bufferCount;
};
cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
}
// Create fence
{
const VkFenceCreateInfo fenceParams =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u // VkFenceCreateFlags flags;
};
fence = createFence(vk, vkDevice, &fenceParams);
}
const VkImageMemoryBarrier preImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
destImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkImageMemoryBarrier postImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
destImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
const VkImageSubresourceRange clearRange =
{
aspectMask, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 levelCount;
0u, // deUint32 baseArrayLayer;
arrayLayers // deUint32 layerCount;
};
// Copy buffer to image
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &preImageBarrier);
if (aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
{
vk.cmdClearColorImage(*cmdBuffer, destImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &clearRange);
}
else
{
vk.cmdClearDepthStencilImage(*cmdBuffer, destImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.depthStencil, 1, &clearRange);
}
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // deUint32 waitSemaphoreCount;
DE_NULL, // const VkSemaphore* pWaitSemaphores;
DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
1u, // deUint32 commandBufferCount;
&cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
0u, // deUint32 signalSemaphoreCount;
DE_NULL // const VkSemaphore* pSignalSemaphores;
};
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */));
}
// Sparse utility function
Move<VkSemaphore> makeSemaphore (const DeviceInterface& vk, const VkDevice device)
{
const VkSemaphoreCreateInfo semaphoreCreateInfo =
{
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
DE_NULL,
0u
};
return createSemaphore(vk, device, &semaphoreCreateInfo);
}
VkExtent3D mipLevelExtents (const VkExtent3D& baseExtents, const deUint32 mipLevel)
{
VkExtent3D result;
result.width = std::max(baseExtents.width >> mipLevel, 1u);
result.height = std::max(baseExtents.height >> mipLevel, 1u);
result.depth = std::max(baseExtents.depth >> mipLevel, 1u);
return result;
}
tcu::UVec3 alignedDivide (const VkExtent3D& extent, const VkExtent3D& divisor)
{
tcu::UVec3 result;
result.x() = extent.width / divisor.width + ((extent.width % divisor.width != 0) ? 1u : 0u);
result.y() = extent.height / divisor.height + ((extent.height % divisor.height != 0) ? 1u : 0u);
result.z() = extent.depth / divisor.depth + ((extent.depth % divisor.depth != 0) ? 1u : 0u);
return result;
}
bool isImageSizeSupported (const VkImageType imageType, const tcu::UVec3& imageSize, const vk::VkPhysicalDeviceLimits& limits)
{
switch (imageType)
{
case VK_IMAGE_TYPE_1D:
return (imageSize.x() <= limits.maxImageDimension1D
&& imageSize.y() == 1
&& imageSize.z() == 1);
case VK_IMAGE_TYPE_2D:
return (imageSize.x() <= limits.maxImageDimension2D
&& imageSize.y() <= limits.maxImageDimension2D
&& imageSize.z() == 1);
case VK_IMAGE_TYPE_3D:
return (imageSize.x() <= limits.maxImageDimension3D
&& imageSize.y() <= limits.maxImageDimension3D
&& imageSize.z() <= limits.maxImageDimension3D);
default:
DE_FATAL("Unknown image type");
return false;
}
}
void ShaderRenderCaseInstance::checkSparseSupport (const VkImageType imageType) const
{
const InstanceInterface& instance = getInstanceInterface();
const VkPhysicalDevice physicalDevice = getPhysicalDevice();
const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(instance, physicalDevice);
if (!deviceFeatures.shaderResourceResidency)
TCU_THROW(NotSupportedError, "Required feature: shaderResourceResidency.");
if (!deviceFeatures.sparseBinding)
TCU_THROW(NotSupportedError, "Required feature: sparseBinding.");
if (imageType == VK_IMAGE_TYPE_2D && !deviceFeatures.sparseResidencyImage2D)
TCU_THROW(NotSupportedError, "Required feature: sparseResidencyImage2D.");
if (imageType == VK_IMAGE_TYPE_3D && !deviceFeatures.sparseResidencyImage3D)
TCU_THROW(NotSupportedError, "Required feature: sparseResidencyImage3D.");
}
void ShaderRenderCaseInstance::uploadSparseImage (const tcu::TextureFormat& texFormat,
const TextureData& textureData,
const tcu::Sampler& refSampler,
const deUint32 mipLevels,
const deUint32 arrayLayers,
const VkImage sparseImage,
const VkImageCreateInfo& imageCreateInfo,
const tcu::UVec3 texSize)
{
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const VkPhysicalDevice physicalDevice = getPhysicalDevice();
const VkQueue queue = getUniversalQueue();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const InstanceInterface& instance = getInstanceInterface();
const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
const VkPhysicalDeviceMemoryProperties deviceMemoryProperties = getPhysicalDeviceMemoryProperties(instance, physicalDevice);
const bool isShadowSampler = refSampler.compare != tcu::Sampler::COMPAREMODE_NONE;
const VkImageAspectFlags aspectMask = isShadowSampler ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
const Unique<VkSemaphore> imageMemoryBindSemaphore(makeSemaphore(vk, vkDevice));
deUint32 bufferSize = 0u;
std::vector<deUint32> offsetMultiples;
offsetMultiples.push_back(4u);
offsetMultiples.push_back(texFormat.getPixelSize());
if (isImageSizeSupported(imageCreateInfo.imageType, texSize, deviceProperties.limits) == false)
TCU_THROW(NotSupportedError, "Image size not supported for device.");
// Calculate buffer size
for (TextureData::const_iterator mit = textureData.begin(); mit != textureData.end(); ++mit)
{
for (TextureLayerData::const_iterator lit = mit->begin(); lit != mit->end(); ++lit)
{
const tcu::ConstPixelBufferAccess& access = *lit;
bufferSize = getNextMultiple(offsetMultiples, bufferSize);
bufferSize += access.getWidth() * access.getHeight() * access.getDepth() * access.getFormat().getPixelSize();
}
}
{
deUint32 sparseMemoryReqCount = 0;
vk.getImageSparseMemoryRequirements(vkDevice, sparseImage, &sparseMemoryReqCount, DE_NULL);
DE_ASSERT(sparseMemoryReqCount != 0);
std::vector<VkSparseImageMemoryRequirements> sparseImageMemoryRequirements;
sparseImageMemoryRequirements.resize(sparseMemoryReqCount);
vk.getImageSparseMemoryRequirements(vkDevice, sparseImage, &sparseMemoryReqCount, &sparseImageMemoryRequirements[0]);
const deUint32 noMatchFound = ~((deUint32)0);
deUint32 colorAspectIndex = noMatchFound;
for (deUint32 memoryReqNdx = 0; memoryReqNdx < sparseMemoryReqCount; ++memoryReqNdx)
{
if (sparseImageMemoryRequirements[memoryReqNdx].formatProperties.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
{
colorAspectIndex = memoryReqNdx;
break;
}
}
if (colorAspectIndex == noMatchFound)
TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT.");
const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vk, vkDevice, sparseImage);
deUint32 memoryType = noMatchFound;
for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemoryProperties.memoryTypeCount; ++memoryTypeNdx)
{
if ((memoryRequirements.memoryTypeBits & (1u << memoryTypeNdx)) != 0 &&
MemoryRequirement::Any.matchesHeap(deviceMemoryProperties.memoryTypes[memoryTypeNdx].propertyFlags))
{
memoryType = memoryTypeNdx;
break;
}
}
if (memoryType == noMatchFound)
TCU_THROW(NotSupportedError, "No matching memory type found.");
if (memoryRequirements.size > deviceProperties.limits.sparseAddressSpaceSize)
TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits.");
// Check if the image format supports sparse oprerations
const std::vector<VkSparseImageFormatProperties> sparseImageFormatPropVec =
getPhysicalDeviceSparseImageFormatProperties(instance, physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType, imageCreateInfo.samples, imageCreateInfo.usage, imageCreateInfo.tiling);
if (sparseImageFormatPropVec.size() == 0)
TCU_THROW(NotSupportedError, "The image format does not support sparse operations.");
const VkSparseImageMemoryRequirements aspectRequirements = sparseImageMemoryRequirements[colorAspectIndex];
const VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity;
std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds;
std::vector<VkSparseMemoryBind> imageMipTailMemoryBinds;
for (deUint32 layerNdx = 0; layerNdx < arrayLayers; ++ layerNdx)
{
for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
{
const VkExtent3D mipExtent = mipLevelExtents(imageCreateInfo.extent, mipLevelNdx);
const tcu::UVec3 numSparseBinds = alignedDivide(mipExtent, imageGranularity);
const tcu::UVec3 lastBlockExtent = tcu::UVec3(mipExtent.width % imageGranularity.width ? mipExtent.width % imageGranularity.width : imageGranularity.width,
mipExtent.height % imageGranularity.height ? mipExtent.height % imageGranularity.height : imageGranularity.height,
mipExtent.depth % imageGranularity.depth ? mipExtent.depth % imageGranularity.depth : imageGranularity.depth );
for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
{
const VkMemoryRequirements allocRequirements =
{
// 28.7.5 alignment shows the block size in bytes
memoryRequirements.alignment, // VkDeviceSize size;
memoryRequirements.alignment, // VkDeviceSize alignment;
memoryRequirements.memoryTypeBits, // uint32_t memoryTypeBits;
};
de::SharedPtr<Allocation> allocation(m_memAlloc.allocate(allocRequirements, MemoryRequirement::Any).release());
m_allocations.push_back(allocation);
VkOffset3D offset;
offset.x = x*imageGranularity.width;
offset.y = y*imageGranularity.height;
offset.z = z*imageGranularity.depth;
VkExtent3D extent;
extent.width = (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : imageGranularity.width;
extent.height = (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : imageGranularity.height;
extent.depth = (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : imageGranularity.depth;
const VkSparseImageMemoryBind imageMemoryBind =
{
{
aspectMask, // VkImageAspectFlags aspectMask;
mipLevelNdx,// uint32_t mipLevel;
layerNdx, // uint32_t arrayLayer;
}, // VkImageSubresource subresource;
offset, // VkOffset3D offset;
extent, // VkExtent3D extent;
allocation->getMemory(), // VkDeviceMemory memory;
allocation->getOffset(), // VkDeviceSize memoryOffset;
0u, // VkSparseMemoryBindFlags flags;
};
imageResidencyMemoryBinds.push_back(imageMemoryBind);
}
}
// Handle MIP tail. There are two cases to consider here:
//
// 1) VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT is requested by the driver: each layer needs a separate tail.
// 2) otherwise: only one tail is needed.
{
if ( imageMipTailMemoryBinds.size() == 0 ||
(imageMipTailMemoryBinds.size() != 0 && (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) == 0))
{
const VkMemoryRequirements allocRequirements =
{
aspectRequirements.imageMipTailSize, // VkDeviceSize size;
memoryRequirements.alignment, // VkDeviceSize alignment;
memoryRequirements.memoryTypeBits, // uint32_t memoryTypeBits;
};
const de::SharedPtr<Allocation> allocation(m_memAlloc.allocate(allocRequirements, MemoryRequirement::Any).release());
const VkSparseMemoryBind imageMipTailMemoryBind =
{
aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride, // VkDeviceSize resourceOffset;
aspectRequirements.imageMipTailSize, // VkDeviceSize size;
allocation->getMemory(), // VkDeviceMemory memory;
allocation->getOffset(), // VkDeviceSize memoryOffset;
0u, // VkSparseMemoryBindFlags flags;
};
m_allocations.push_back(allocation);
imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
}
}
}
VkBindSparseInfo bindSparseInfo =
{
VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType;
DE_NULL, //const void* pNext;
0u, //deUint32 waitSemaphoreCount;
DE_NULL, //const VkSemaphore* pWaitSemaphores;
0u, //deUint32 bufferBindCount;
DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds;
0u, //deUint32 imageOpaqueBindCount;
DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
0u, //deUint32 imageBindCount;
DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds;
1u, //deUint32 signalSemaphoreCount;
&imageMemoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores;
};
VkSparseImageMemoryBindInfo imageResidencyBindInfo;
VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
if (imageResidencyMemoryBinds.size() > 0)
{
imageResidencyBindInfo.image = sparseImage;
imageResidencyBindInfo.bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size());
imageResidencyBindInfo.pBinds = &imageResidencyMemoryBinds[0];
bindSparseInfo.imageBindCount = 1u;
bindSparseInfo.pImageBinds = &imageResidencyBindInfo;
}
if (imageMipTailMemoryBinds.size() > 0)
{
imageMipTailBindInfo.image = sparseImage;
imageMipTailBindInfo.bindCount = static_cast<deUint32>(imageMipTailMemoryBinds.size());
imageMipTailBindInfo.pBinds = &imageMipTailMemoryBinds[0];
bindSparseInfo.imageOpaqueBindCount = 1u;
bindSparseInfo.pImageOpaqueBinds = &imageMipTailBindInfo;
}
VK_CHECK(vk.queueBindSparse(queue, 1u, &bindSparseInfo, DE_NULL));
}
Move<VkCommandPool> cmdPool;
Move<VkCommandBuffer> cmdBuffer;
// Create command pool
{
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
}
{
// Create command buffer
const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCommandPool commandPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
1u, // deUint32 bufferCount;
};
cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
}
// Create source buffer
const VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
0u, // deUint32 queueFamilyIndexCount;
DE_NULL, // const deUint32* pQueueFamilyIndices;
};
Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &bufferParams);
de::MovePtr<Allocation> bufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
// Barriers for copying buffer to image
const VkBufferMemoryBarrier preBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*buffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
bufferSize // VkDeviceSize size;
};
const VkImageMemoryBarrier preImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
sparseImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkImageMemoryBarrier postImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
sparseImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
aspectMask, // VkImageAspect aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}
};
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
std::vector<VkBufferImageCopy> copyRegions;
// Get copy regions and write buffer data
{
deUint32 layerDataOffset = 0;
deUint8* destPtr = (deUint8*)bufferAlloc->getHostPtr();
for (size_t levelNdx = 0; levelNdx < textureData.size(); levelNdx++)
{
const TextureLayerData& layerData = textureData[levelNdx];
for (size_t layerNdx = 0; layerNdx < layerData.size(); layerNdx++)
{
layerDataOffset = getNextMultiple(offsetMultiples, layerDataOffset);
const tcu::ConstPixelBufferAccess& access = layerData[layerNdx];
const tcu::PixelBufferAccess destAccess (access.getFormat(), access.getSize(), destPtr + layerDataOffset);
const VkBufferImageCopy layerRegion =
{
layerDataOffset, // VkDeviceSize bufferOffset;
(deUint32)access.getWidth(), // deUint32 bufferRowLength;
(deUint32)access.getHeight(), // deUint32 bufferImageHeight;
{ // VkImageSubresourceLayers imageSubresource;
aspectMask, // VkImageAspectFlags aspectMask;
(deUint32)levelNdx, // uint32_t mipLevel;
(deUint32)layerNdx, // uint32_t baseArrayLayer;
1u // uint32_t layerCount;
},
{ 0u, 0u, 0u }, // VkOffset3D imageOffset;
{ // VkExtent3D imageExtent;
(deUint32)access.getWidth(),
(deUint32)access.getHeight(),
(deUint32)access.getDepth()
}
};
copyRegions.push_back(layerRegion);
tcu::copy(destAccess, access);
layerDataOffset += access.getWidth() * access.getHeight() * access.getDepth() * access.getFormat().getPixelSize();
}
}
}
// Copy buffer to image
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &preBufferBarrier, 1, &preImageBarrier);
vk.cmdCopyBufferToImage(*cmdBuffer, *buffer, sparseImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)copyRegions.size(), copyRegions.data());
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
const VkPipelineStageFlags pipelineStageFlags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
1u, // deUint32 waitSemaphoreCount;
&imageMemoryBindSemaphore.get(), // const VkSemaphore* pWaitSemaphores;
&pipelineStageFlags, // const VkPipelineStageFlags* pWaitDstStageMask;
1u, // deUint32 commandBufferCount;
&cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
0u, // deUint32 signalSemaphoreCount;
DE_NULL // const VkSemaphore* pSignalSemaphores;
};
const VkFenceCreateInfo fenceParams =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u // VkFenceCreateFlags flags;
};
Move<VkFence> fence = createFence(vk, vkDevice, &fenceParams);
try
{
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */));
}
catch (...)
{
VK_CHECK(vk.deviceWaitIdle(vkDevice));
throw;
}
}
void ShaderRenderCaseInstance::useSampler (deUint32 bindingLocation, deUint32 textureId)
{
DE_ASSERT(textureId < m_textures.size());
const TextureBinding& textureBinding = *m_textures[textureId];
const TextureBinding::Type textureType = textureBinding.getType();
const tcu::Sampler& refSampler = textureBinding.getSampler();
const TextureBinding::Parameters& textureParams = textureBinding.getParameters();
const bool isMSTexture = textureParams.samples != vk::VK_SAMPLE_COUNT_1_BIT;
deUint32 mipLevels = 1u;
deUint32 arrayLayers = 1u;
tcu::TextureFormat texFormat;
tcu::UVec3 texSize;
TextureData textureData;
if (textureType == TextureBinding::TYPE_2D)
{
const tcu::Texture2D& texture = textureBinding.get2D();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getWidth(), texture.getHeight(), 1u);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = 1u;
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
textureData[level].push_back(texture.getLevel(level));
}
}
else if (textureType == TextureBinding::TYPE_CUBE_MAP)
{
const tcu::TextureCube& texture = textureBinding.getCube();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getSize(), texture.getSize(), 1u);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = 6u;
static const tcu::CubeFace cubeFaceMapping[tcu::CUBEFACE_LAST] =
{
tcu::CUBEFACE_POSITIVE_X,
tcu::CUBEFACE_NEGATIVE_X,
tcu::CUBEFACE_POSITIVE_Y,
tcu::CUBEFACE_NEGATIVE_Y,
tcu::CUBEFACE_POSITIVE_Z,
tcu::CUBEFACE_NEGATIVE_Z
};
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
{
tcu::CubeFace face = cubeFaceMapping[faceNdx];
if (texture.isLevelEmpty(face, level))
continue;
textureData[level].push_back(texture.getLevelFace(level, face));
}
}
}
else if (textureType == TextureBinding::TYPE_2D_ARRAY)
{
const tcu::Texture2DArray& texture = textureBinding.get2DArray();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getWidth(), texture.getHeight(), 1u);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = (deUint32)texture.getNumLayers();
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
const tcu::ConstPixelBufferAccess& levelLayers = texture.getLevel(level);
const deUint32 layerSize = levelLayers.getWidth() * levelLayers.getHeight() * levelLayers.getFormat().getPixelSize();
for (deUint32 layer = 0; layer < arrayLayers; ++layer)
{
const deUint32 layerOffset = layerSize * layer;
tcu::ConstPixelBufferAccess layerData (levelLayers.getFormat(), levelLayers.getWidth(), levelLayers.getHeight(), 1, (deUint8*)levelLayers.getDataPtr() + layerOffset);
textureData[level].push_back(layerData);
}
}
}
else if (textureType == TextureBinding::TYPE_3D)
{
const tcu::Texture3D& texture = textureBinding.get3D();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getWidth(), texture.getHeight(), texture.getDepth());
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = 1u;
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
textureData[level].push_back(texture.getLevel(level));
}
}
else if (textureType == TextureBinding::TYPE_1D)
{
const tcu::Texture1D& texture = textureBinding.get1D();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getWidth(), 1, 1);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = 1u;
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
textureData[level].push_back(texture.getLevel(level));
}
}
else if (textureType == TextureBinding::TYPE_1D_ARRAY)
{
const tcu::Texture1DArray& texture = textureBinding.get1DArray();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getWidth(), 1, 1);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = (deUint32)texture.getNumLayers();
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
const tcu::ConstPixelBufferAccess& levelLayers = texture.getLevel(level);
const deUint32 layerSize = levelLayers.getWidth() * levelLayers.getFormat().getPixelSize();
for (deUint32 layer = 0; layer < arrayLayers; ++layer)
{
const deUint32 layerOffset = layerSize * layer;
tcu::ConstPixelBufferAccess layerData (levelLayers.getFormat(), levelLayers.getWidth(), 1, 1, (deUint8*)levelLayers.getDataPtr() + layerOffset);
textureData[level].push_back(layerData);
}
}
}
else if (textureType == TextureBinding::TYPE_CUBE_ARRAY)
{
const tcu::TextureCubeArray& texture = textureBinding.getCubeArray();
texFormat = texture.getFormat();
texSize = tcu::UVec3(texture.getSize(), texture.getSize(), 1);
mipLevels = isMSTexture ? 1u : (deUint32)texture.getNumLevels();
arrayLayers = texture.getDepth();
textureData.resize(mipLevels);
for (deUint32 level = 0; level < mipLevels; ++level)
{
if (texture.isLevelEmpty(level))
continue;
const tcu::ConstPixelBufferAccess& levelLayers = texture.getLevel(level);
const deUint32 layerSize = levelLayers.getWidth() * levelLayers.getHeight() * levelLayers.getFormat().getPixelSize();
for (deUint32 layer = 0; layer < arrayLayers; ++layer)
{
const deUint32 layerOffset = layerSize * layer;
tcu::ConstPixelBufferAccess layerData (levelLayers.getFormat(), levelLayers.getWidth(), levelLayers.getHeight(), 1, (deUint8*)levelLayers.getDataPtr() + layerOffset);
textureData[level].push_back(layerData);
}
}
}
else
{
TCU_THROW(InternalError, "Invalid texture type");
}
createSamplerUniform(bindingLocation, textureType, textureBinding.getParameters().initialization, texFormat, texSize, textureData, refSampler, mipLevels, arrayLayers, textureParams);
}
void ShaderRenderCaseInstance::setPushConstantRanges (const deUint32 rangeCount, const vk::VkPushConstantRange* const pcRanges)
{
m_pushConstantRanges.clear();
for (deUint32 i = 0; i < rangeCount; ++i)
{
m_pushConstantRanges.push_back(pcRanges[i]);
}
}
void ShaderRenderCaseInstance::updatePushConstants (vk::VkCommandBuffer, vk::VkPipelineLayout)
{
}
void ShaderRenderCaseInstance::createSamplerUniform (deUint32 bindingLocation,
TextureBinding::Type textureType,
TextureBinding::Init textureInit,
const tcu::TextureFormat& texFormat,
const tcu::UVec3 texSize,
const TextureData& textureData,
const tcu::Sampler& refSampler,
deUint32 mipLevels,
deUint32 arrayLayers,
TextureBinding::Parameters textureParams)
{
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const bool isShadowSampler = refSampler.compare != tcu::Sampler::COMPAREMODE_NONE;
const VkImageAspectFlags aspectMask = isShadowSampler ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
const VkImageViewType imageViewType = textureTypeToImageViewType(textureType);
const VkImageType imageType = viewTypeToImageType(imageViewType);
const VkFormat format = mapTextureFormat(texFormat);
const bool isCube = imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
VkImageCreateFlags imageCreateFlags = isCube ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (VkImageCreateFlags)0;
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Move<VkImage> vkTexture;
de::MovePtr<Allocation> allocation;
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
{
checkSparseSupport(imageType);
imageCreateFlags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
}
// Create image
const VkImageCreateInfo imageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
imageCreateFlags, // VkImageCreateFlags flags;
imageType, // VkImageType imageType;
format, // VkFormat format;
{ // VkExtent3D extent;
texSize.x(),
texSize.y(),
texSize.z()
},
mipLevels, // deUint32 mipLevels;
arrayLayers, // deUint32 arrayLayers;
textureParams.samples, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
imageUsageFlags, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
vkTexture = createImage(vk, vkDevice, &imageParams);
allocation = m_memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *vkTexture), MemoryRequirement::Any);
if (m_imageBackingMode != IMAGE_BACKING_MODE_SPARSE)
{
VK_CHECK(vk.bindImageMemory(vkDevice, *vkTexture, allocation->getMemory(), allocation->getOffset()));
}
switch (textureInit)
{
case TextureBinding::INIT_UPLOAD_DATA:
{
// upload*Image functions use cmdCopyBufferToImage, which is invalid for multisample images
DE_ASSERT(textureParams.samples == VK_SAMPLE_COUNT_1_BIT);
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
{
uploadSparseImage(texFormat, textureData, refSampler, mipLevels, arrayLayers, *vkTexture, imageParams, texSize);
}
else
{
// Upload texture data
uploadImage(texFormat, textureData, refSampler, mipLevels, arrayLayers, *vkTexture);
}
break;
}
case TextureBinding::INIT_CLEAR:
clearImage(refSampler, mipLevels, arrayLayers, *vkTexture);
break;
default:
DE_FATAL("Impossible");
}
// Create sampler
const VkSamplerCreateInfo samplerParams = mapSampler(refSampler, texFormat);
Move<VkSampler> sampler = createSampler(vk, vkDevice, &samplerParams);
const deUint32 baseMipLevel = textureParams.baseMipLevel;
const vk::VkComponentMapping components = textureParams.componentMapping;
const VkImageViewCreateInfo viewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
NULL, // const voide* pNext;
0u, // VkImageViewCreateFlags flags;
*vkTexture, // VkImage image;
imageViewType, // VkImageViewType viewType;
format, // VkFormat format;
components, // VkChannelMapping channels;
{
aspectMask, // VkImageAspectFlags aspectMask;
baseMipLevel, // deUint32 baseMipLevel;
mipLevels - baseMipLevel, // deUint32 mipLevels;
0, // deUint32 baseArraySlice;
arrayLayers // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
Move<VkImageView> imageView = createImageView(vk, vkDevice, &viewParams);
const vk::VkDescriptorImageInfo descriptor =
{
sampler.get(), // VkSampler sampler;
imageView.get(), // VkImageView imageView;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout imageLayout;
};
de::MovePtr<SamplerUniform> uniform(new SamplerUniform());
uniform->type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
uniform->descriptor = descriptor;
uniform->location = bindingLocation;
uniform->image = VkImageSp(new vk::Unique<VkImage>(vkTexture));
uniform->imageView = VkImageViewSp(new vk::Unique<VkImageView>(imageView));
uniform->sampler = VkSamplerSp(new vk::Unique<VkSampler>(sampler));
uniform->alloc = AllocationSp(allocation.release());
m_descriptorSetLayoutBuilder->addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_ALL, DE_NULL);
m_descriptorPoolBuilder->addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
m_uniformInfos.push_back(UniformInfoSp(new de::UniquePtr<UniformInfo>(uniform)));
}
void ShaderRenderCaseInstance::setupDefaultInputs (void)
{
/* Configuration of the vertex input attributes:
a_position is at location 0
a_coords is at location 1
a_unitCoords is at location 2
a_one is at location 3
User attributes starts from at the location 4.
*/
DE_ASSERT(m_quadGrid);
const QuadGrid& quadGrid = *m_quadGrid;
addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(tcu::Vec4), quadGrid.getNumVertices(), quadGrid.getPositions());
addAttribute(1u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(tcu::Vec4), quadGrid.getNumVertices(), quadGrid.getCoords());
addAttribute(2u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(tcu::Vec4), quadGrid.getNumVertices(), quadGrid.getUnitCoords());
addAttribute(3u, VK_FORMAT_R32_SFLOAT, sizeof(float), quadGrid.getNumVertices(), quadGrid.getAttribOne());
static const struct
{
BaseAttributeType type;
int userNdx;
} userAttributes[] =
{
{ A_IN0, 0 },
{ A_IN1, 1 },
{ A_IN2, 2 },
{ A_IN3, 3 }
};
static const struct
{
BaseAttributeType matrixType;
int numCols;
int numRows;
} matrices[] =
{
{ MAT2, 2, 2 },
{ MAT2x3, 2, 3 },
{ MAT2x4, 2, 4 },
{ MAT3x2, 3, 2 },
{ MAT3, 3, 3 },
{ MAT3x4, 3, 4 },
{ MAT4x2, 4, 2 },
{ MAT4x3, 4, 3 },
{ MAT4, 4, 4 }
};
for (size_t attrNdx = 0; attrNdx < m_enabledBaseAttributes.size(); attrNdx++)
{
for (int userNdx = 0; userNdx < DE_LENGTH_OF_ARRAY(userAttributes); userNdx++)
{
if (userAttributes[userNdx].type != m_enabledBaseAttributes[attrNdx].type)
continue;
addAttribute(m_enabledBaseAttributes[attrNdx].location, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(tcu::Vec4), quadGrid.getNumVertices(), quadGrid.getUserAttrib(userNdx));
}
for (int matNdx = 0; matNdx < DE_LENGTH_OF_ARRAY(matrices); matNdx++)
{
if (matrices[matNdx].matrixType != m_enabledBaseAttributes[attrNdx].type)
continue;
const int numCols = matrices[matNdx].numCols;
for (int colNdx = 0; colNdx < numCols; colNdx++)
{
addAttribute(m_enabledBaseAttributes[attrNdx].location + colNdx, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(4 * sizeof(float)), quadGrid.getNumVertices(), quadGrid.getUserAttrib(colNdx));
}
}
}
}
void ShaderRenderCaseInstance::render (deUint32 numVertices,
deUint32 numTriangles,
const deUint16* indices,
const tcu::Vec4& constCoords)
{
render(numVertices, numTriangles * 3, indices, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, constCoords);
}
void ShaderRenderCaseInstance::render (deUint32 numVertices,
deUint32 numIndices,
const deUint16* indices,
VkPrimitiveTopology topology,
const tcu::Vec4& constCoords)
{
const VkDevice vkDevice = getDevice();
const DeviceInterface& vk = getDeviceInterface();
const VkQueue queue = getUniversalQueue();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
vk::Move<vk::VkImage> colorImage;
de::MovePtr<vk::Allocation> colorImageAlloc;
vk::Move<vk::VkImageView> colorImageView;
vk::Move<vk::VkImage> resolvedImage;
de::MovePtr<vk::Allocation> resolvedImageAlloc;
vk::Move<vk::VkImageView> resolvedImageView;
vk::Move<vk::VkRenderPass> renderPass;
vk::Move<vk::VkFramebuffer> framebuffer;
vk::Move<vk::VkPipelineLayout> pipelineLayout;
vk::Move<vk::VkPipeline> graphicsPipeline;
vk::Move<vk::VkShaderModule> vertexShaderModule;
vk::Move<vk::VkShaderModule> fragmentShaderModule;
vk::Move<vk::VkBuffer> indexBuffer;
de::MovePtr<vk::Allocation> indexBufferAlloc;
vk::Move<vk::VkDescriptorSetLayout> descriptorSetLayout;
vk::Move<vk::VkDescriptorPool> descriptorPool;
vk::Move<vk::VkDescriptorSet> descriptorSet;
vk::Move<vk::VkCommandPool> cmdPool;
vk::Move<vk::VkCommandBuffer> cmdBuffer;
vk::Move<vk::VkFence> fence;
// Create color image
{
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VkImageFormatProperties properties;
if ((getInstanceInterface().getPhysicalDeviceImageFormatProperties(getPhysicalDevice(),
m_colorFormat,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
imageUsage,
0u,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
{
TCU_THROW(NotSupportedError, "Format not supported");
}
if ((properties.sampleCounts & m_sampleCount) != m_sampleCount)
{
TCU_THROW(NotSupportedError, "Format not supported");
}
const VkImageCreateInfo colorImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_colorFormat, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arraySize;
m_sampleCount, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
imageUsage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
colorImage = createImage(vk, vkDevice, &colorImageParams);
// Allocate and bind color image memory
colorImageAlloc = m_memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *colorImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *colorImage, colorImageAlloc->getMemory(), colorImageAlloc->getOffset()));
}
// Create color attachment view
{
const VkImageViewCreateInfo colorImageViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*colorImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_colorFormat, // VkFormat format;
{
VK_COMPONENT_SWIZZLE_R, // VkChannelSwizzle r;
VK_COMPONENT_SWIZZLE_G, // VkChannelSwizzle g;
VK_COMPONENT_SWIZZLE_B, // VkChannelSwizzle b;
VK_COMPONENT_SWIZZLE_A // VkChannelSwizzle a;
}, // VkChannelMapping channels;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0, // deUint32 baseMipLevel;
1, // deUint32 mipLevels;
0, // deUint32 baseArraySlice;
1 // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
colorImageView = createImageView(vk, vkDevice, &colorImageViewParams);
}
if (isMultiSampling())
{
// Resolved Image
{
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImageFormatProperties properties;
if ((getInstanceInterface().getPhysicalDeviceImageFormatProperties(getPhysicalDevice(),
m_colorFormat,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
imageUsage,
0,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
{
TCU_THROW(NotSupportedError, "Format not supported");
}
const VkImageCreateInfo imageCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_colorFormat, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
imageUsage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
resolvedImage = vk::createImage(vk, vkDevice, &imageCreateInfo, DE_NULL);
resolvedImageAlloc = m_memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *resolvedImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *resolvedImage, resolvedImageAlloc->getMemory(), resolvedImageAlloc->getOffset()));
}
// Resolved Image View
{
const VkImageViewCreateInfo imageViewCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*resolvedImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_colorFormat, // VkFormat format;
{
VK_COMPONENT_SWIZZLE_R, // VkChannelSwizzle r;
VK_COMPONENT_SWIZZLE_G, // VkChannelSwizzle g;
VK_COMPONENT_SWIZZLE_B, // VkChannelSwizzle b;
VK_COMPONENT_SWIZZLE_A // VkChannelSwizzle a;
},
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
resolvedImageView = vk::createImageView(vk, vkDevice, &imageViewCreateInfo, DE_NULL);
}
}
// Create render pass
{
const VkAttachmentDescription attachmentDescription[] =
{
{
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
m_colorFormat, // VkFormat format;
m_sampleCount, // deUint32 samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
},
{
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
m_colorFormat, // VkFormat format;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
}
};
const VkAttachmentReference attachmentReference =
{
0u, // deUint32 attachment;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
};
const VkAttachmentReference resolveAttachmentRef =
{
1u, // deUint32 attachment;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
};
const VkSubpassDescription subpassDescription =
{
0u, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // deUint32 inputCount;
DE_NULL, // constVkAttachmentReference* pInputAttachments;
1u, // deUint32 colorCount;
&attachmentReference, // constVkAttachmentReference* pColorAttachments;
isMultiSampling() ? &resolveAttachmentRef : DE_NULL,// constVkAttachmentReference* pResolveAttachments;
DE_NULL, // VkAttachmentReference depthStencilAttachment;
0u, // deUint32 preserveCount;
DE_NULL // constVkAttachmentReference* pPreserveAttachments;
};
const VkRenderPassCreateInfo renderPassParams =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkRenderPassCreateFlags flags;
isMultiSampling() ? 2u : 1u, // deUint32 attachmentCount;
attachmentDescription, // const VkAttachmentDescription* pAttachments;
1u, // deUint32 subpassCount;
&subpassDescription, // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL // const VkSubpassDependency* pDependencies;
};
renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
}
// Create framebuffer
{
const VkImageView attachments[] =
{
*colorImageView,
*resolvedImageView
};
const VkFramebufferCreateInfo framebufferParams =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkFramebufferCreateFlags)0,
*renderPass, // VkRenderPass renderPass;
isMultiSampling() ? 2u : 1u, // deUint32 attachmentCount;
attachments, // const VkImageView* pAttachments;
(deUint32)m_renderSize.x(), // deUint32 width;
(deUint32)m_renderSize.y(), // deUint32 height;
1u // deUint32 layers;
};
framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
}
// Create descriptors
{
setupUniforms(constCoords);
descriptorSetLayout = m_descriptorSetLayoutBuilder->build(vk, vkDevice);
if (!m_uniformInfos.empty())
{
descriptorPool = m_descriptorPoolBuilder->build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
const VkDescriptorSetAllocateInfo allocInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
*descriptorPool,
1u,
&descriptorSetLayout.get(),
};
descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
}
for (deUint32 i = 0; i < m_uniformInfos.size(); i++)
{
const UniformInfo* uniformInfo = m_uniformInfos[i].get()->get();
deUint32 location = uniformInfo->location;
if (uniformInfo->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
{
const BufferUniform* bufferInfo = dynamic_cast<const BufferUniform*>(uniformInfo);
m_descriptorSetUpdateBuilder->writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(location), uniformInfo->type, &bufferInfo->descriptor);
}
else if (uniformInfo->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
const SamplerUniform* samplerInfo = dynamic_cast<const SamplerUniform*>(uniformInfo);
m_descriptorSetUpdateBuilder->writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(location), uniformInfo->type, &samplerInfo->descriptor);
}
else
DE_FATAL("Impossible");
}
m_descriptorSetUpdateBuilder->update(vk, vkDevice);
}
// Create pipeline layout
{
const VkPushConstantRange* const pcRanges = m_pushConstantRanges.empty() ? DE_NULL : &m_pushConstantRanges[0];
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineLayoutCreateFlags)0,
1u, // deUint32 descriptorSetCount;
&*descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts;
deUint32(m_pushConstantRanges.size()), // deUint32 pushConstantRangeCount;
pcRanges // const VkPushConstantRange* pPushConstantRanges;
};
pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
}
// Create shaders
{
vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get(m_vertexShaderName), 0);
fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get(m_fragmentShaderName), 0);
}
// Create pipeline
{
const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
{
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStage stage;
*vertexShaderModule, // VkShader shader;
"main",
DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
},
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStage stage;
*fragmentShaderModule, // VkShader shader;
"main",
DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
}
};
// Add test case specific attributes
if (m_attribFunc)
m_attribFunc(*this, numVertices);
// Add base attributes
setupDefaultInputs();
const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineVertexInputStateCreateFlags)0,
(deUint32)m_vertexBindingDescription.size(), // deUint32 bindingCount;
&m_vertexBindingDescription[0], // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
(deUint32)m_vertexAttributeDescription.size(), // deUint32 attributeCount;
&m_vertexAttributeDescription[0], // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineInputAssemblyStateCreateFlags)0,
topology, // VkPrimitiveTopology topology;
false // VkBool32 primitiveRestartEnable;
};
const VkViewport viewport =
{
0.0f, // float originX;
0.0f, // float originY;
(float)m_renderSize.x(), // float width;
(float)m_renderSize.y(), // float height;
0.0f, // float minDepth;
1.0f // float maxDepth;
};
const VkRect2D scissor =
{
{
0u, // deUint32 x;
0u, // deUint32 y;
}, // VkOffset2D offset;
{
m_renderSize.x(), // deUint32 width;
m_renderSize.y(), // deUint32 height;
}, // VkExtent2D extent;
};
const VkPipelineViewportStateCreateInfo viewportStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineViewportStateCreateFlags flags;
1u, // deUint32 viewportCount;
&viewport, // const VkViewport* pViewports;
1u, // deUint32 scissorsCount;
&scissor, // const VkRect2D* pScissors;
};
const VkPipelineRasterizationStateCreateInfo rasterStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineRasterizationStateCreateFlags)0,
false, // VkBool32 depthClipEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkFillMode fillMode;
VK_CULL_MODE_NONE, // VkCullMode cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
false, // VkBool32 depthBiasEnable;
0.0f, // float depthBias;
0.0f, // float depthBiasClamp;
0.0f, // float slopeScaledDepthBias;
1.0f, // float lineWidth;
};
const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineMultisampleStateCreateFlags flags;
m_sampleCount, // VkSampleCountFlagBits rasterizationSamples;
VK_FALSE, // VkBool32 sampleShadingEnable;
0.0f, // float minSampleShading;
DE_NULL, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable;
VK_FALSE // VkBool32 alphaToOneEnable;
};
const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
false, // VkBool32 blendEnable;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor;
VK_BLEND_FACTOR_ZERO, // VkBlend destBlendColor;
VK_BLEND_OP_ADD, // VkBlendOp blendOpColor;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha;
VK_BLEND_FACTOR_ZERO, // VkBlend destBlendAlpha;
VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha;
(VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT), // VkChannelFlags channelWriteMask;
};
const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineColorBlendStateCreateFlags)0,
false, // VkBool32 logicOpEnable;
VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1u, // deUint32 attachmentCount;
&colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
{ 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4];
};
const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineCreateFlags flags;
2u, // deUint32 stageCount;
shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages;
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
&inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState;
&multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
(const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
*pipelineLayout, // VkPipelineLayout layout;
*renderPass, // VkRenderPass renderPass;
0u, // deUint32 subpass;
0u, // VkPipeline basePipelineHandle;
0u // deInt32 basePipelineIndex;
};
graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
}
// Create vertex indices buffer
if (numIndices != 0)
{
const VkDeviceSize indexBufferSize = numIndices * sizeof(deUint16);
const VkBufferCreateInfo indexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
indexBufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
indexBuffer = createBuffer(vk, vkDevice, &indexBufferParams);
indexBufferAlloc = m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexBufferAlloc->getMemory(), indexBufferAlloc->getOffset()));
// Load vertice indices into buffer
deMemcpy(indexBufferAlloc->getHostPtr(), indices, (size_t)indexBufferSize);
flushMappedMemoryRange(vk, vkDevice, indexBufferAlloc->getMemory(), indexBufferAlloc->getOffset(), indexBufferSize);
}
// Create command pool
{
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
}
// Create command buffer
{
const VkCommandBufferAllocateInfo cmdBufferParams =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCmdPool cmdPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level;
1u // deUint32 bufferCount;
};
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkCmdBufferOptimizeFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
const VkClearValue clearValues = makeClearValueColorF32(m_clearColor.x(),
m_clearColor.y(),
m_clearColor.z(),
m_clearColor.w());
const VkRenderPassBeginInfo renderPassBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*renderPass, // VkRenderPass renderPass;
*framebuffer, // VkFramebuffer framebuffer;
{ { 0, 0 }, {m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea;
1, // deUint32 clearValueCount;
&clearValues, // const VkClearValue* pClearValues;
};
cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
{
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*colorImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}
};
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, DE_NULL, 1, &imageBarrier);
if (isMultiSampling()) {
// add multisample barrier
const VkImageMemoryBarrier multiSampleImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*resolvedImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}
};
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, DE_NULL, 1, &multiSampleImageBarrier);
}
}
vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
updatePushConstants(*cmdBuffer, *pipelineLayout);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
if (!m_uniformInfos.empty())
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1, &*descriptorSet, 0u, DE_NULL);
const deUint32 numberOfVertexAttributes = (deUint32)m_vertexBuffers.size();
const std::vector<VkDeviceSize> offsets(numberOfVertexAttributes, 0);
std::vector<VkBuffer> buffers(numberOfVertexAttributes);
for (size_t i = 0; i < numberOfVertexAttributes; i++)
{
buffers[i] = m_vertexBuffers[i].get()->get();
}
vk.cmdBindVertexBuffers(*cmdBuffer, 0, numberOfVertexAttributes, &buffers[0], &offsets[0]);
if (numIndices != 0)
{
vk.cmdBindIndexBuffer(*cmdBuffer, *indexBuffer, 0, VK_INDEX_TYPE_UINT16);
vk.cmdDrawIndexed(*cmdBuffer, numIndices, 1, 0, 0, 0);
}
else
vk.cmdDraw(*cmdBuffer, numVertices, 1, 0, 1);
vk.cmdEndRenderPass(*cmdBuffer);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
}
// Create fence
{
const VkFenceCreateInfo fenceParams =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u // VkFenceCreateFlags flags;
};
fence = createFence(vk, vkDevice, &fenceParams);
}
// Execute Draw
{
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO,
DE_NULL,
0u,
(const VkSemaphore*)DE_NULL,
(const VkPipelineStageFlags*)DE_NULL,
1u,
&cmdBuffer.get(),
0u,
(const VkSemaphore*)DE_NULL,
};
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity*/));
}
// Read back the result
{
const tcu::TextureFormat resultFormat = mapVkFormat(m_colorFormat);
const VkDeviceSize imageSizeBytes = (VkDeviceSize)(resultFormat.getPixelSize() * m_renderSize.x() * m_renderSize.y());
const VkBufferCreateInfo readImageBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
imageSizeBytes, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
const Unique<VkBuffer> readImageBuffer (createBuffer(vk, vkDevice, &readImageBufferParams));
const de::UniquePtr<Allocation> readImageBufferMemory (m_memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
// Copy image to buffer
const VkCommandBufferAllocateInfo cmdBufferParams =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCmdPool cmdPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level;
1u // deUint32 bufferCount;
};
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkCmdBufferOptimizeFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
const Move<VkCommandBuffer> resultCmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
const VkBufferImageCopy copyParams =
{
0u, // VkDeviceSize bufferOffset;
(deUint32)m_renderSize.x(), // deUint32 bufferRowLength;
(deUint32)m_renderSize.y(), // deUint32 bufferImageHeight;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspect aspect;
0u, // deUint32 mipLevel;
0u, // deUint32 arraySlice;
1u, // deUint32 arraySize;
}, // VkImageSubresourceCopy imageSubresource;
{ 0u, 0u, 0u }, // VkOffset3D imageOffset;
{ m_renderSize.x(), m_renderSize.y(), 1u } // VkExtent3D imageExtent;
};
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO,
DE_NULL,
0u,
(const VkSemaphore*)DE_NULL,
(const VkPipelineStageFlags*)DE_NULL,
1u,
&resultCmdBuffer.get(),
0u,
(const VkSemaphore*)DE_NULL,
};
VK_CHECK(vk.beginCommandBuffer(*resultCmdBuffer, &cmdBufferBeginInfo));
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
isMultiSampling() ? *resolvedImage : *colorImage, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
const VkBufferMemoryBarrier bufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*readImageBuffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
imageSizeBytes // VkDeviceSize size;
};
vk.cmdPipelineBarrier(*resultCmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
vk.cmdCopyImageToBuffer(*resultCmdBuffer, isMultiSampling() ? *resolvedImage : *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
vk.cmdPipelineBarrier(*resultCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
VK_CHECK(vk.endCommandBuffer(*resultCmdBuffer));
VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */));
invalidateMappedMemoryRange(vk, vkDevice, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset(), imageSizeBytes);
const tcu::ConstPixelBufferAccess resultAccess (resultFormat, m_renderSize.x(), m_renderSize.y(), 1, readImageBufferMemory->getHostPtr());
m_resultImage.setStorage(resultFormat, m_renderSize.x(), m_renderSize.y());
tcu::copy(m_resultImage.getAccess(), resultAccess);
}
}
void ShaderRenderCaseInstance::computeVertexReference (tcu::Surface& result, const QuadGrid& quadGrid)
{
DE_ASSERT(m_evaluator);
// Buffer info.
const int width = result.getWidth();
const int height = result.getHeight();
const int gridSize = quadGrid.getGridSize();
const int stride = gridSize + 1;
const bool hasAlpha = true; // \todo [2015-09-07 elecro] add correct alpha check
ShaderEvalContext evalCtx (quadGrid);
// Evaluate color for each vertex.
std::vector<tcu::Vec4> colors ((gridSize + 1) * (gridSize + 1));
for (int y = 0; y < gridSize+1; y++)
for (int x = 0; x < gridSize+1; x++)
{
const float sx = (float)x / (float)gridSize;
const float sy = (float)y / (float)gridSize;
const int vtxNdx = ((y * (gridSize+1)) + x);
evalCtx.reset(sx, sy);
m_evaluator->evaluate(evalCtx);
DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader.
tcu::Vec4 color = evalCtx.color;
if (!hasAlpha)
color.w() = 1.0f;
colors[vtxNdx] = color;
}
// Render quads.
for (int y = 0; y < gridSize; y++)
for (int x = 0; x < gridSize; x++)
{
const float x0 = (float)x / (float)gridSize;
const float x1 = (float)(x + 1) / (float)gridSize;
const float y0 = (float)y / (float)gridSize;
const float y1 = (float)(y + 1) / (float)gridSize;
const float sx0 = x0 * (float)width;
const float sx1 = x1 * (float)width;
const float sy0 = y0 * (float)height;
const float sy1 = y1 * (float)height;
const float oosx = 1.0f / (sx1 - sx0);
const float oosy = 1.0f / (sy1 - sy0);
const int ix0 = deCeilFloatToInt32(sx0 - 0.5f);
const int ix1 = deCeilFloatToInt32(sx1 - 0.5f);
const int iy0 = deCeilFloatToInt32(sy0 - 0.5f);
const int iy1 = deCeilFloatToInt32(sy1 - 0.5f);
const int v00 = (y * stride) + x;
const int v01 = (y * stride) + x + 1;
const int v10 = ((y + 1) * stride) + x;
const int v11 = ((y + 1) * stride) + x + 1;
const tcu::Vec4 c00 = colors[v00];
const tcu::Vec4 c01 = colors[v01];
const tcu::Vec4 c10 = colors[v10];
const tcu::Vec4 c11 = colors[v11];
//printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
for (int iy = iy0; iy < iy1; iy++)
for (int ix = ix0; ix < ix1; ix++)
{
DE_ASSERT(deInBounds32(ix, 0, width));
DE_ASSERT(deInBounds32(iy, 0, height));
const float sfx = (float)ix + 0.5f;
const float sfy = (float)iy + 0.5f;
const float fx1 = deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f);
const float fy1 = deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f);
// Triangle quad interpolation.
const bool tri = fx1 + fy1 <= 1.0f;
const float tx = tri ? fx1 : (1.0f-fx1);
const float ty = tri ? fy1 : (1.0f-fy1);
const tcu::Vec4& t0 = tri ? c00 : c11;
const tcu::Vec4& t1 = tri ? c01 : c10;
const tcu::Vec4& t2 = tri ? c10 : c01;
const tcu::Vec4 color = t0 + (t1-t0)*tx + (t2-t0)*ty;
result.setPixel(ix, iy, tcu::RGBA(color));
}
}
}
void ShaderRenderCaseInstance::computeFragmentReference (tcu::Surface& result, const QuadGrid& quadGrid)
{
DE_ASSERT(m_evaluator);
// Buffer info.
const int width = result.getWidth();
const int height = result.getHeight();
const bool hasAlpha = true; // \todo [2015-09-07 elecro] add correct alpha check
ShaderEvalContext evalCtx (quadGrid);
// Render.
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
const float sx = ((float)x + 0.5f) / (float)width;
const float sy = ((float)y + 0.5f) / (float)height;
evalCtx.reset(sx, sy);
m_evaluator->evaluate(evalCtx);
// Select either clear color or computed color based on discarded bit.
tcu::Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color;
if (!hasAlpha)
color.w() = 1.0f;
result.setPixel(x, y, tcu::RGBA(color));
}
}
bool ShaderRenderCaseInstance::compareImages (const tcu::Surface& resImage, const tcu::Surface& refImage, float errorThreshold)
{
return tcu::fuzzyCompare(m_context.getTestContext().getLog(), "ComparisonResult", "Image comparison result", refImage, resImage, errorThreshold, tcu::COMPARE_LOG_RESULT);
}
} // sr
} // vkt