blob: c5855493a3d312802c69a31f0069cd50235125bf [file] [log] [blame]
#ifndef _VKTSHADERRENDER_HPP
#define _VKTSHADERRENDER_HPP
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* 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 "tcuTexture.hpp"
#include "tcuSurface.hpp"
#include "tcuMaybe.hpp"
#include "deMemory.h"
#include "deSharedPtr.hpp"
#include "deUniquePtr.hpp"
#include "vkDefs.hpp"
#include "vkRefUtil.hpp"
#include "vkPrograms.hpp"
#include "vkRef.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkPlatform.hpp"
#include "vktTestCaseUtil.hpp"
namespace vkt
{
namespace sr
{
class LineStream
{
public:
LineStream (int indent = 0) { m_indent = indent; }
~LineStream (void) {}
const char* str (void) const { m_string = m_stream.str(); return m_string.c_str(); }
LineStream& operator<< (const char* line) { for (int i = 0; i < m_indent; i++) { m_stream << "\t"; } m_stream << line << "\n"; return *this; }
private:
int m_indent;
std::ostringstream m_stream;
mutable std::string m_string;
};
class QuadGrid;
class ShaderRenderCaseInstance;
class TextureBinding
{
public:
enum Type
{
TYPE_NONE = 0,
TYPE_1D,
TYPE_2D,
TYPE_3D,
TYPE_CUBE_MAP,
TYPE_1D_ARRAY,
TYPE_2D_ARRAY,
TYPE_CUBE_ARRAY,
TYPE_LAST
};
enum Init
{
INIT_UPLOAD_DATA,
INIT_CLEAR,
INIT_LAST
};
struct MinMaxLod
{
float minLod;
float maxLod;
MinMaxLod (float min, float max) : minLod(min), maxLod(max) {}
};
struct Parameters
{
deUint32 baseMipLevel;
vk::VkComponentMapping componentMapping;
vk::VkSampleCountFlagBits samples;
Init initialization;
tcu::Maybe<MinMaxLod> minMaxLod;
Parameters (deUint32 baseMipLevel_ = 0,
vk::VkComponentMapping componentMapping_ = vk::makeComponentMappingRGBA(),
vk::VkSampleCountFlagBits samples_ = vk::VK_SAMPLE_COUNT_1_BIT,
Init initialization_ = INIT_UPLOAD_DATA,
const tcu::Maybe<MinMaxLod>& minMaxLod_ = tcu::Nothing)
: baseMipLevel (baseMipLevel_)
, componentMapping (componentMapping_)
, samples (samples_)
, initialization (initialization_)
, minMaxLod (minMaxLod_)
{
}
};
TextureBinding (const tcu::Archive& archive,
const char* filename,
const Type type,
const tcu::Sampler& sampler);
TextureBinding (const tcu::Texture1D* tex1D, const tcu::Sampler& sampler);
TextureBinding (const tcu::Texture2D* tex2D, const tcu::Sampler& sampler);
TextureBinding (const tcu::Texture3D* tex3D, const tcu::Sampler& sampler);
TextureBinding (const tcu::TextureCube* texCube, const tcu::Sampler& sampler);
TextureBinding (const tcu::Texture1DArray* tex1DArray, const tcu::Sampler& sampler);
TextureBinding (const tcu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler);
TextureBinding (const tcu::TextureCubeArray* texCubeArray, const tcu::Sampler& sampler);
~TextureBinding (void);
Type getType (void) const { return m_type; }
const tcu::Sampler& getSampler (void) const { return m_sampler; }
const tcu::Texture1D& get1D (void) const { DE_ASSERT(getType() == TYPE_1D && m_binding.tex1D != NULL); return *m_binding.tex1D; }
const tcu::Texture2D& get2D (void) const { DE_ASSERT(getType() == TYPE_2D && m_binding.tex2D != NULL); return *m_binding.tex2D; }
const tcu::Texture3D& get3D (void) const { DE_ASSERT(getType() == TYPE_3D && m_binding.tex3D != NULL); return *m_binding.tex3D; }
const tcu::TextureCube& getCube (void) const { DE_ASSERT(getType() == TYPE_CUBE_MAP && m_binding.texCube != NULL); return *m_binding.texCube; }
const tcu::Texture1DArray& get1DArray (void) const { DE_ASSERT(getType() == TYPE_1D_ARRAY && m_binding.tex1DArray != NULL); return *m_binding.tex1DArray; }
const tcu::Texture2DArray& get2DArray (void) const { DE_ASSERT(getType() == TYPE_2D_ARRAY && m_binding.tex2DArray != NULL); return *m_binding.tex2DArray; }
const tcu::TextureCubeArray& getCubeArray (void) const { DE_ASSERT(getType() == TYPE_CUBE_ARRAY && m_binding.texCubeArray != NULL); return *m_binding.texCubeArray; }
void setParameters (const Parameters& params) { m_params = params; }
const Parameters& getParameters (void) const { return m_params; }
private:
TextureBinding (const TextureBinding&); // not allowed!
TextureBinding& operator= (const TextureBinding&); // not allowed!
static de::MovePtr<tcu::Texture2D> loadTexture2D (const tcu::Archive& archive, const char* filename);
Type m_type;
tcu::Sampler m_sampler;
Parameters m_params;
union
{
const tcu::Texture1D* tex1D;
const tcu::Texture2D* tex2D;
const tcu::Texture3D* tex3D;
const tcu::TextureCube* texCube;
const tcu::Texture1DArray* tex1DArray;
const tcu::Texture2DArray* tex2DArray;
const tcu::TextureCubeArray* texCubeArray;
} m_binding;
};
typedef de::SharedPtr<TextureBinding> TextureBindingSp;
// ShaderEvalContext.
class ShaderEvalContext
{
public:
// Limits.
enum
{
MAX_USER_ATTRIBS = 4,
MAX_TEXTURES = 4
};
struct ShaderSampler
{
tcu::Sampler sampler;
const tcu::Texture1D* tex1D;
const tcu::Texture2D* tex2D;
const tcu::Texture3D* tex3D;
const tcu::TextureCube* texCube;
const tcu::Texture1DArray* tex1DArray;
const tcu::Texture2DArray* tex2DArray;
const tcu::TextureCubeArray* texCubeArray;
inline ShaderSampler (void)
: tex1D (DE_NULL)
, tex2D (DE_NULL)
, tex3D (DE_NULL)
, texCube (DE_NULL)
, tex1DArray (DE_NULL)
, tex2DArray (DE_NULL)
, texCubeArray (DE_NULL)
{
}
};
ShaderEvalContext (const QuadGrid& quadGrid);
~ShaderEvalContext (void);
void reset (float sx, float sy);
// Inputs.
tcu::Vec4 coords;
tcu::Vec4 unitCoords;
tcu::Vec4 constCoords;
tcu::Vec4 in[MAX_USER_ATTRIBS];
ShaderSampler textures[MAX_TEXTURES];
// Output.
tcu::Vec4 color;
bool isDiscarded;
// Functions.
inline void discard (void) { isDiscarded = true; }
tcu::Vec4 texture2D (int unitNdx, const tcu::Vec2& coords);
private:
const QuadGrid& m_quadGrid;
};
typedef void (*ShaderEvalFunc) (ShaderEvalContext& c);
inline void evalCoordsPassthroughX (ShaderEvalContext& c) { c.color.x() = c.coords.x(); }
inline void evalCoordsPassthroughXY (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1); }
inline void evalCoordsPassthroughXYZ (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
inline void evalCoordsPassthrough (ShaderEvalContext& c) { c.color = c.coords; }
inline void evalCoordsSwizzleWZYX (ShaderEvalContext& c) { c.color = c.coords.swizzle(3,2,1,0); }
// ShaderEvaluator
// Either inherit a class with overridden evaluate() or just pass in an evalFunc.
class ShaderEvaluator
{
public:
ShaderEvaluator (void);
ShaderEvaluator (const ShaderEvalFunc evalFunc);
virtual ~ShaderEvaluator (void);
virtual void evaluate (ShaderEvalContext& ctx) const;
private:
ShaderEvaluator (const ShaderEvaluator&); // not allowed!
ShaderEvaluator& operator= (const ShaderEvaluator&); // not allowed!
const ShaderEvalFunc m_evalFunc;
};
// UniformSetup
typedef void (*UniformSetupFunc) (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords);
class UniformSetup
{
public:
UniformSetup (void);
UniformSetup (const UniformSetupFunc setup);
virtual ~UniformSetup (void);
virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
private:
UniformSetup (const UniformSetup&); // not allowed!
UniformSetup& operator= (const UniformSetup&); // not allowed!
const UniformSetupFunc m_setupFunc;
};
typedef void (*AttributeSetupFunc) (ShaderRenderCaseInstance& instance, deUint32 numVertices);
class ShaderRenderCase : public vkt::TestCase
{
public:
ShaderRenderCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const bool isVertexCase,
const ShaderEvalFunc evalFunc,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc);
ShaderRenderCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const bool isVertexCase,
const ShaderEvaluator* evaluator,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc);
virtual ~ShaderRenderCase (void);
virtual void initPrograms (vk::SourceCollections& programCollection) const;
virtual TestInstance* createInstance (Context& context) const;
protected:
std::string m_vertShaderSource;
std::string m_fragShaderSource;
const bool m_isVertexCase;
const de::UniquePtr<const ShaderEvaluator> m_evaluator;
const de::UniquePtr<const UniformSetup> m_uniformSetup;
const AttributeSetupFunc m_attribFunc;
};
enum BaseUniformType
{
// Bool
UB_FALSE,
UB_TRUE,
// BVec4
UB4_FALSE,
UB4_TRUE,
// Integers
UI_ZERO,
UI_ONE,
UI_TWO,
UI_THREE,
UI_FOUR,
UI_FIVE,
UI_SIX,
UI_SEVEN,
UI_EIGHT,
UI_ONEHUNDREDONE,
// IVec2
UI2_MINUS_ONE,
UI2_ZERO,
UI2_ONE,
UI2_TWO,
UI2_THREE,
UI2_FOUR,
UI2_FIVE,
// IVec3
UI3_MINUS_ONE,
UI3_ZERO,
UI3_ONE,
UI3_TWO,
UI3_THREE,
UI3_FOUR,
UI3_FIVE,
// IVec4
UI4_MINUS_ONE,
UI4_ZERO,
UI4_ONE,
UI4_TWO,
UI4_THREE,
UI4_FOUR,
UI4_FIVE,
// Float
UF_ZERO,
UF_ONE,
UF_TWO,
UF_THREE,
UF_FOUR,
UF_FIVE,
UF_SIX,
UF_SEVEN,
UF_EIGHT,
UF_HALF,
UF_THIRD,
UF_FOURTH,
UF_FIFTH,
UF_SIXTH,
UF_SEVENTH,
UF_EIGHTH,
// Vec2
UV2_MINUS_ONE,
UV2_ZERO,
UV2_ONE,
UV2_TWO,
UV2_THREE,
UV2_HALF,
// Vec3
UV3_MINUS_ONE,
UV3_ZERO,
UV3_ONE,
UV3_TWO,
UV3_THREE,
UV3_HALF,
// Vec4
UV4_MINUS_ONE,
UV4_ZERO,
UV4_ONE,
UV4_TWO,
UV4_THREE,
UV4_HALF,
UV4_BLACK,
UV4_GRAY,
UV4_WHITE,
// Last
U_LAST
};
enum BaseAttributeType
{
// User attributes
A_IN0,
A_IN1,
A_IN2,
A_IN3,
// Matrices
MAT2,
MAT2x3,
MAT2x4,
MAT3x2,
MAT3,
MAT3x4,
MAT4x2,
MAT4x3,
MAT4
};
// ShaderRenderCaseInstance.
class ShaderRenderCaseInstance : public vkt::TestInstance
{
public:
enum ImageBackingMode
{
IMAGE_BACKING_MODE_REGULAR = 0,
IMAGE_BACKING_MODE_SPARSE,
};
// Default wertex and fragment grid sizes are used by a large collection of tests
// to generate input sets. Some tests might change their behavior if the
// default grid size values are altered, so care should be taken to confirm that
// any changes to default values do not produce regressions.
// If a particular tests needs to use a different grid size value, rather than
// modifying the default grid size values for all tests, it is recommended that
// the test specifies the required grid size using the gridSize parameter in the
// ShaderRenderCaseInstance constuctor instead.
enum
{
GRID_SIZE_DEFAULTS = 0,
GRID_SIZE_DEFAULT_VERTEX = 90,
GRID_SIZE_DEFAULT_FRAGMENT = 4,
};
ShaderRenderCaseInstance (Context& context);
ShaderRenderCaseInstance (Context& context,
const bool isVertexCase,
const ShaderEvaluator& evaluator,
const UniformSetup& uniformSetup,
const AttributeSetupFunc attribFunc,
const ImageBackingMode imageBackingMode = IMAGE_BACKING_MODE_REGULAR,
const deUint32 gridSize = static_cast<deUint32>(GRID_SIZE_DEFAULTS),
const bool fuzzyCompare = true);
virtual ~ShaderRenderCaseInstance (void);
virtual tcu::TestStatus iterate (void);
void addAttribute (deUint32 bindingLocation,
vk::VkFormat format,
deUint32 sizePerElement,
deUint32 count,
const void* data);
void useAttribute (deUint32 bindingLocation,
BaseAttributeType type);
template<typename T>
void addUniform (deUint32 bindingLocation,
vk::VkDescriptorType descriptorType,
const T& data);
void addUniform (deUint32 bindingLocation,
vk::VkDescriptorType descriptorType,
size_t dataSize,
const void* data);
void useUniform (deUint32 bindingLocation,
BaseUniformType type);
void useSampler (deUint32 bindingLocation,
deUint32 textureId);
static const tcu::Vec4 getDefaultConstCoords (void) { return tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f); }
void setPushConstantRanges (const deUint32 rangeCount, const vk::VkPushConstantRange* const pcRanges);
virtual void updatePushConstants (vk::VkCommandBuffer commandBuffer, vk::VkPipelineLayout pipelineLayout);
protected:
ShaderRenderCaseInstance (Context& context,
const bool isVertexCase,
const ShaderEvaluator* evaluator,
const UniformSetup* uniformSetup,
const AttributeSetupFunc attribFunc,
const ImageBackingMode imageBackingMode = IMAGE_BACKING_MODE_REGULAR,
const deUint32 gridSize = static_cast<deUint32>(GRID_SIZE_DEFAULTS));
virtual void setup (void);
virtual void setupUniforms (const tcu::Vec4& constCoords);
virtual void setupDefaultInputs (void);
void render (deUint32 numVertices,
deUint32 numTriangles,
const deUint16* indices,
const tcu::Vec4& constCoords = getDefaultConstCoords());
void render (deUint32 numVertices,
deUint32 numIndices,
const deUint16* indices,
vk::VkPrimitiveTopology topology,
const tcu::Vec4& constCoords = getDefaultConstCoords());
const tcu::TextureLevel& getResultImage (void) const { return m_resultImage; }
const tcu::UVec2 getViewportSize (void) const;
void setSampleCount (vk::VkSampleCountFlagBits sampleCount);
bool isMultiSampling (void) const;
ImageBackingMode m_imageBackingMode;
deUint32 m_quadGridSize;
protected:
vk::Allocator& m_memAlloc;
const tcu::Vec4 m_clearColor;
const bool m_isVertexCase;
std::vector<tcu::Mat4> m_userAttribTransforms;
std::vector<TextureBindingSp> m_textures;
std::string m_vertexShaderName;
std::string m_fragmentShaderName;
tcu::UVec2 m_renderSize;
vk::VkFormat m_colorFormat;
de::SharedPtr<vk::Unique<vk::VkCommandPool> > m_externalCommandPool;
private:
typedef std::vector<tcu::ConstPixelBufferAccess> TextureLayerData;
typedef std::vector<TextureLayerData> TextureData;
void uploadImage (const tcu::TextureFormat& texFormat,
const TextureData& textureData,
const tcu::Sampler& refSampler,
deUint32 mipLevels,
deUint32 arrayLayers,
vk::VkImage destImage);
void clearImage (const tcu::Sampler& refSampler,
deUint32 mipLevels,
deUint32 arrayLayers,
vk::VkImage destImage);
void checkSparseSupport (const vk::VkImageCreateInfo& imageInfo) const;
#ifndef CTS_USES_VULKANSC
void uploadSparseImage (const tcu::TextureFormat& texFormat,
const TextureData& textureData,
const tcu::Sampler& refSampler,
const deUint32 mipLevels,
const deUint32 arrayLayers,
const vk::VkImage sparseImage,
const vk::VkImageCreateInfo& imageCreateInfo,
const tcu::UVec3 texSize);
#endif // CTS_USES_VULKANSC
void 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);
void setupUniformData (deUint32 bindingLocation, size_t size, const void* dataPtr);
void computeVertexReference (tcu::Surface& result, const QuadGrid& quadGrid);
void computeFragmentReference (tcu::Surface& result, const QuadGrid& quadGrid);
bool compareImages (const tcu::Surface& resImage,
const tcu::Surface& refImage,
float errorThreshold);
private:
const ShaderEvaluator* m_evaluator;
const UniformSetup* m_uniformSetup;
const AttributeSetupFunc m_attribFunc;
de::MovePtr<QuadGrid> m_quadGrid;
tcu::TextureLevel m_resultImage;
struct EnabledBaseAttribute
{
deUint32 location;
BaseAttributeType type;
};
std::vector<EnabledBaseAttribute> m_enabledBaseAttributes;
de::MovePtr<vk::DescriptorSetLayoutBuilder> m_descriptorSetLayoutBuilder;
de::MovePtr<vk::DescriptorPoolBuilder> m_descriptorPoolBuilder;
de::MovePtr<vk::DescriptorSetUpdateBuilder> m_descriptorSetUpdateBuilder;
typedef de::SharedPtr<vk::Unique<vk::VkBuffer> > VkBufferSp;
typedef de::SharedPtr<vk::Unique<vk::VkImage> > VkImageSp;
typedef de::SharedPtr<vk::Unique<vk::VkImageView> > VkImageViewSp;
typedef de::SharedPtr<vk::Unique<vk::VkSampler> > VkSamplerSp;
typedef de::SharedPtr<vk::Allocation> AllocationSp;
class UniformInfo
{
public:
UniformInfo (void) {}
virtual ~UniformInfo (void) {}
vk::VkDescriptorType type;
deUint32 location;
};
class BufferUniform : public UniformInfo
{
public:
BufferUniform (void) {}
virtual ~BufferUniform (void) {}
VkBufferSp buffer;
AllocationSp alloc;
vk::VkDescriptorBufferInfo descriptor;
};
class SamplerUniform : public UniformInfo
{
public:
SamplerUniform (void) {}
virtual ~SamplerUniform (void) {}
VkImageSp image;
VkImageViewSp imageView;
VkSamplerSp sampler;
AllocationSp alloc;
vk::VkDescriptorImageInfo descriptor;
};
typedef de::SharedPtr<de::UniquePtr<UniformInfo> > UniformInfoSp;
std::vector<UniformInfoSp> m_uniformInfos;
std::vector< de::SharedPtr<vk::Allocation> > m_allocations;
std::vector<vk::VkVertexInputBindingDescription> m_vertexBindingDescription;
std::vector<vk::VkVertexInputAttributeDescription> m_vertexAttributeDescription;
std::vector<VkBufferSp> m_vertexBuffers;
std::vector<AllocationSp> m_vertexBufferAllocs;
vk::VkSampleCountFlagBits m_sampleCount;
std::vector<vk::VkPushConstantRange> m_pushConstantRanges;
bool m_fuzzyCompare;
protected:
vk::VkDevice getDevice (void) const;
deUint32 getUniversalQueueFamilyIndex (void) const;
deUint32 getSparseQueueFamilyIndex (void) const;
const vk::DeviceInterface& getDeviceInterface (void) const;
vk::VkQueue getUniversalQueue (void) const;
vk::VkQueue getSparseQueue (void) const;
vk::VkPhysicalDevice getPhysicalDevice (void) const;
const vk::InstanceInterface& getInstanceInterface (void) const;
vk::Allocator& getAllocator (void) const;
};
template<typename T>
void ShaderRenderCaseInstance::addUniform (deUint32 bindingLocation, vk::VkDescriptorType descriptorType, const T& data)
{
addUniform(bindingLocation, descriptorType, sizeof(T), &data);
}
vk::VkImageViewType textureTypeToImageViewType (TextureBinding::Type type);
vk::VkImageType viewTypeToImageType (vk::VkImageViewType type);
vk::VkImageUsageFlags textureUsageFlags (void);
vk::VkImageCreateFlags textureCreateFlags (vk::VkImageViewType viewType, ShaderRenderCaseInstance::ImageBackingMode backingMode);
} // sr
} // vkt
#endif // _VKTSHADERRENDER_HPP