blob: 16633ddd1f660bb3b67981bb078ef941efe2c70d [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 "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include <vector>
#include <string>
namespace vkt
{
namespace sr
{
using namespace vk;
namespace
{
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_quadGridSize (static_cast<deUint32>(GRID_SIZE_DEFAULT_FRAGMENT))
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (false)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (MAX_RENDER_WIDTH, MAX_RENDER_HEIGHT)
, 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,
const deUint32 gridSize)
: vkt::TestInstance (context)
, m_imageBackingMode (imageBackingMode)
, m_quadGridSize (gridSize == static_cast<deUint32>(GRID_SIZE_DEFAULTS)
? (isVertexCase
? static_cast<deUint32>(GRID_SIZE_DEFAULT_VERTEX)
: static_cast<deUint32>(GRID_SIZE_DEFAULT_FRAGMENT))
: gridSize)
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (isVertexCase)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (MAX_RENDER_WIDTH, MAX_RENDER_HEIGHT)
, 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,
const deUint32 gridSize)
: vkt::TestInstance (context)
, m_imageBackingMode (imageBackingMode)
, m_quadGridSize (gridSize == static_cast<deUint32>(GRID_SIZE_DEFAULTS)
? (isVertexCase
? static_cast<deUint32>(GRID_SIZE_DEFAULT_VERTEX)
: static_cast<deUint32>(GRID_SIZE_DEFAULT_FRAGMENT))
: gridSize)
, m_memAlloc (getAllocator())
, m_clearColor (DEFAULT_CLEAR_COLOR)
, m_isVertexCase (isVertexCase)
, m_vertexShaderName ("vert")
, m_fragmentShaderName ("frag")
, m_renderSize (MAX_RENDER_WIDTH, MAX_RENDER_HEIGHT)
, m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
, m_evaluator (evaluator)
, m_uniformSetup (uniformSetup)
, m_attribFunc (attribFunc)
, m_sampleCount (VK_SAMPLE_COUNT_1_BIT)
{
}
vk::Allocator& ShaderRenderCaseInstance::getAllocator (void) const
{
return m_context.getDefaultAllocator();
}
ShaderRenderCaseInstance::~ShaderRenderCaseInstance (void)
{
}
VkDevice ShaderRenderCaseInstance::getDevice (void) const
{
return m_context.getDevice();
}
deUint32 ShaderRenderCaseInstance::getUniversalQueueFamilyIndex (void) const
{
return m_context.getUniversalQueueFamilyIndex();
}
deUint32 ShaderRenderCaseInstance::getSparseQueueFamilyIndex (void) const
{
return m_context.getSparseQueueFamilyIndex();
}
const DeviceInterface& ShaderRenderCaseInstance::getDeviceInterface (void) const
{
return m_context.getDeviceInterface();
}
VkQueue ShaderRenderCaseInstance::getUniversalQueue (void) const
{
return m_context.getUniversalQueue();
}
VkQueue ShaderRenderCaseInstance::getSparseQueue (void) const
{
return m_context.getSparseQueue();
}
VkPhysicalDevice ShaderRenderCaseInstance::getPhysicalDevice (void) const
{
return m_context.getPhysicalDevice();
}
const InstanceInterface& ShaderRenderCaseInstance::getInstanceInterface (void) const
{
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_quadGridSize, 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.2f);
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);
flushAlloc(vk, vkDevice, *alloc);
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);
flushAlloc(vk, vkDevice, *alloc);
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;
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()));
}
// 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();
}
}
}
flushAlloc(vk, vkDevice, *bufferAlloc);
copyBufferToImage(vk, vkDevice, queue, queueFamilyIndex, *buffer, bufferSize, copyRegions, DE_NULL, aspectMask, mipLevels, arrayLayers, destImage);
}
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;
VkClearValue clearValue;
deMemset(&clearValue, 0, sizeof(clearValue));
// Create command pool and buffer
cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
cmdBuffer = allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
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 VkImageSubresourceRange clearRange =
{
aspectMask, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 levelCount;
0u, // deUint32 baseArrayLayer;
arrayLayers // deUint32 layerCount;
};
// Copy buffer to image
beginCommandBuffer(vk, *cmdBuffer);
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_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
endCommandBuffer(vk, *cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, cmdBuffer.get());
}
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 VkImageCreateInfo& imageInfo) const
{
const InstanceInterface& instance = getInstanceInterface();
const VkPhysicalDevice physicalDevice = getPhysicalDevice();
const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(instance, physicalDevice);
const std::vector<VkSparseImageFormatProperties> sparseImageFormatPropVec = getPhysicalDeviceSparseImageFormatProperties(
instance, physicalDevice, imageInfo.format, imageInfo.imageType, imageInfo.samples, imageInfo.usage, imageInfo.tiling);
if (!deviceFeatures.shaderResourceResidency)
TCU_THROW(NotSupportedError, "Required feature: shaderResourceResidency.");
if (!deviceFeatures.sparseBinding)
TCU_THROW(NotSupportedError, "Required feature: sparseBinding.");
if (imageInfo.imageType == VK_IMAGE_TYPE_2D && !deviceFeatures.sparseResidencyImage2D)
TCU_THROW(NotSupportedError, "Required feature: sparseResidencyImage2D.");
if (imageInfo.imageType == VK_IMAGE_TYPE_3D && !deviceFeatures.sparseResidencyImage3D)
TCU_THROW(NotSupportedError, "Required feature: sparseResidencyImage3D.");
if (sparseImageFormatPropVec.size() == 0)
TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
}
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 VkQueue sparseQueue = getSparseQueue();
const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
const InstanceInterface& instance = getInstanceInterface();
const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(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(createSemaphore(vk, vkDevice));
Move<VkBuffer> buffer;
deUint32 bufferSize = 0u;
de::MovePtr<Allocation> bufferAlloc;
std::vector<VkBufferImageCopy> copyRegions;
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.");
allocateAndBindSparseImage(vk, vkDevice, physicalDevice, instance, imageCreateInfo, *imageMemoryBindSemaphore, sparseQueue, m_memAlloc, m_allocations, texFormat, sparseImage);
// 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()));
}
// 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();
}
}
}
copyBufferToImage(vk, vkDevice, queue, queueFamilyIndex, *buffer, bufferSize, copyRegions, &(*imageMemoryBindSemaphore), aspectMask, mipLevels, arrayLayers, sparseImage);
}
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 deUint32 sparseFamilyIndex = (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE) ? getSparseQueueFamilyIndex() : queueFamilyIndex;
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 VkSharingMode sharingMode = (queueFamilyIndex != sparseFamilyIndex) ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE;
const VkFormat format = mapTextureFormat(texFormat);
const bool isCube = imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
const deUint32 queueIndexCount = (queueFamilyIndex != sparseFamilyIndex) ? 2 : 1;
const deUint32 queueIndices[] =
{
queueFamilyIndex,
sparseFamilyIndex
};
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)
{
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;
sharingMode, // VkSharingMode sharingMode;
queueIndexCount, // deUint32 queueFamilyIndexCount;
queueIndices, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
if (m_imageBackingMode == IMAGE_BACKING_MODE_SPARSE)
{
checkSparseSupport(imageParams);
}
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;
// 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
{
// 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 std::vector<VkViewport> viewports (1, makeViewport(m_renderSize));
const std::vector<VkRect2D> scissors (1, makeRect2D(m_renderSize));
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;
};
graphicsPipeline = makeGraphicsPipeline(vk, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*pipelineLayout, // const VkPipelineLayout pipelineLayout
*vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
topology, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleStateParams); // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
}
// 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);
flushAlloc(vk, vkDevice, *indexBufferAlloc);
}
// Create command pool
cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
// Create command buffer
{
cmdBuffer = allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
beginCommandBuffer(vk, *cmdBuffer);
{
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);
}
}
beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
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);
endRenderPass(vk, *cmdBuffer);
endCommandBuffer(vk, *cmdBuffer);
}
// Execute Draw
submitCommandsAndWait(vk, vkDevice, queue, cmdBuffer.get());
// 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 Move<VkCommandBuffer> resultCmdBuffer = allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
beginCommandBuffer(vk, *resultCmdBuffer);
copyImageToBuffer(vk, *resultCmdBuffer, isMultiSampling() ? *resolvedImage : *colorImage, *readImageBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()));
endCommandBuffer(vk, *resultCmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, resultCmdBuffer.get());
invalidateAlloc(vk, vkDevice, *readImageBufferMemory);
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_EVERYTHING);
}
} // sr
} // vkt