blob: b5f246a65792ab231a4905a107891259382f461f [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 "deMemory.h"
#include "deSharedPtr.hpp"
#include "deUniquePtr.hpp"
#include "vkDefs.hpp"
#include "vkPrograms.hpp"
#include "vkRef.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.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_2D,
TYPE_CUBE_MAP,
TYPE_2D_ARRAY,
TYPE_3D,
TYPE_LAST
};
TextureBinding (const tcu::Archive& archive,
const char* filename,
const Type type,
const tcu::Sampler& sampler);
~TextureBinding (void);
Type getType (void) const { return m_type; }
const tcu::Sampler& getSampler (void) const { return m_sampler; }
const tcu::Texture2D& get2D (void) const { DE_ASSERT(getType() == TYPE_2D && m_binding.tex2D !=NULL); return *m_binding.tex2D; }
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;
union
{
const tcu::Texture2D* tex2D;
} 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::Texture2D* tex2D;
const tcu::TextureCube* texCube;
const tcu::Texture2DArray* tex2DArray;
const tcu::Texture3D* tex3D;
inline ShaderSampler (void)
: tex2D (DE_NULL)
, texCube (DE_NULL)
, tex2DArray(DE_NULL)
, tex3D (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
};
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:
ShaderRenderCaseInstance (Context& context,
const bool isVertexCase,
const ShaderEvaluator& evaluator,
const UniformSetup& uniformSetup,
const AttributeSetupFunc attribFunc);
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 useSampler2D (deUint32 bindingLocation,
deUint32 textureId);
protected:
virtual void setup (void);
virtual void setupUniforms (const tcu::Vec4& constCoords);
const tcu::UVec2 getViewportSize (void) const;
std::vector<tcu::Mat4> m_userAttribTransforms;
const tcu::Vec4 m_clearColor;
std::vector<TextureBindingSp> m_textures;
vk::Allocator& m_memAlloc;
private:
void setupTextures (void);
de::MovePtr<vk::Allocation> uploadImage2D (const tcu::Texture2D& refTexture,
const vk::VkImage& vkTexture);
vk::Move<vk::VkImage> createImage2D (const tcu::Texture2D& texture,
const vk::VkFormat format,
const vk::VkImageUsageFlags usage,
const vk::VkImageTiling tiling);
void copyTilingImageToOptimal (const vk::VkImage& srcImage,
const vk::VkImage& dstImage,
deUint32 width,
deUint32 height);
void setupUniformData (deUint32 bindingLocation, size_t size, const void* dataPtr);
void setupDefaultInputs (const QuadGrid& quadGrid);
void render (tcu::Surface& result, const QuadGrid& quadGrid);
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);
const bool m_isVertexCase;
const ShaderEvaluator& m_evaluator;
const UniformSetup& m_uniformSetup;
const AttributeSetupFunc m_attribFunc;
struct EnabledBaseAttribute
{
deUint32 location;
BaseAttributeType type;
};
std::vector<EnabledBaseAttribute> m_enabledBaseAttributes;
const tcu::UVec2 m_renderSize;
const vk::VkFormat m_colorFormat;
vk::Move<vk::VkImage> m_colorImage;
de::MovePtr<vk::Allocation> m_colorImageAlloc;
vk::Move<vk::VkImageView> m_colorImageView;
vk::Move<vk::VkRenderPass> m_renderPass;
vk::Move<vk::VkFramebuffer> m_framebuffer;
vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
vk::Move<vk::VkPipeline> m_graphicsPipeline;
vk::Move<vk::VkShaderModule> m_vertexShaderModule;
vk::Move<vk::VkShaderModule> m_fragmentShaderModule;
vk::Move<vk::VkBuffer> m_indiceBuffer;
de::MovePtr<vk::Allocation> m_indiceBufferAlloc;
vk::Move<vk::VkDescriptorSetLayout> m_descriptorSetLayout;
vk::Move<vk::VkDescriptorPool> m_descriptorPool;
vk::Move<vk::VkDescriptorSet> m_descriptorSet;
vk::Move<vk::VkCommandPool> m_cmdPool;
vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
vk::Move<vk::VkFence> m_fence;
vk::DescriptorSetLayoutBuilder m_descriptorSetLayoutBuilder;
vk::DescriptorPoolBuilder m_descriptorPoolBuilder;
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<vk::VkVertexInputBindingDescription> m_vertexBindingDescription;
std::vector<vk::VkVertexInputAttributeDescription> m_vertexattributeDescription;
std::vector<VkBufferSp> m_vertexBuffers;
std::vector<AllocationSp> m_vertexBufferAllocs;
};
template<typename T>
void ShaderRenderCaseInstance::addUniform (deUint32 bindingLocation, vk::VkDescriptorType descriptorType, const T& data)
{
addUniform(bindingLocation, descriptorType, sizeof(T), &data);
}
} // sr
} // vkt
#endif // _VKTSHADERRENDER_HPP