1 /*------------------------------------------------------------------------
2 * Copyright (c) 2015 The Khronos Group Inc.
3 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and/or associated documentation files (the
7 * "Materials"), to deal in the Materials without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Materials, and to
10 * permit persons to whom the Materials are furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice(s) and this permission notice shall be included
14 * in all copies or substantial portions of the Materials.
16 * The Materials are Confidential Information as defined by the
17 * Khronos Membership Agreement until designated non-confidential by Khronos,
18 * at which point this condition clause shall be removed.
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
30 * \brief Vulkan ShaderRenderCase
31 *//*--------------------------------------------------------------------*/
33 #include "vktShaderRenderCase.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuVector.hpp"
38 #include "tcuTestLog.hpp"
47 namespace shaderrendercase
53 static const int GRID_SIZE = 64;
54 static const int MAX_RENDER_WIDTH = 128;
55 static const int MAX_RENDER_HEIGHT = 112;
56 static const tcu::Vec4 DEFAULT_CLEAR_COLOR = tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f);
63 QuadGrid (int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords, const vector<Mat4>& userAttribTransforms
64 /*, const vector<TextureBinding>& textures*/);
67 int getGridSize (void) const { return m_gridSize; }
68 int getNumVertices (void) const { return m_numVertices; }
69 int getNumTriangles (void) const { return m_numTriangles; }
70 const Vec4& getConstCoords (void) const { return m_constCoords; }
71 const vector<Mat4> getUserAttribTransforms (void) const { return m_userAttribTransforms; }
73 //const vector<TextureBinding>& getTextures (void) const { return m_textures; }
75 const Vec4* getPositions (void) const { return &m_positions[0]; }
76 const float* getAttribOne (void) const { return &m_attribOne[0]; }
77 const Vec4* getCoords (void) const { return &m_coords[0]; }
78 const Vec4* getUnitCoords (void) const { return &m_unitCoords[0]; }
79 const Vec4* getUserAttrib (int attribNdx) const { return &m_userAttribs[attribNdx][0]; }
80 const deUint16* getIndices (void) const { return &m_indices[0]; }
82 Vec4 getCoords (float sx, float sy) const;
83 Vec4 getUnitCoords (float sx, float sy) const;
85 int getNumUserAttribs (void) const { return (int)m_userAttribTransforms.size(); }
86 Vec4 getUserAttrib (int attribNdx, float sx, float sy) const;
93 vector<Mat4> m_userAttribTransforms;
95 // vector<TextureBinding> m_textures;
97 vector<Vec4> m_screenPos;
98 vector<Vec4> m_positions;
99 vector<Vec4> m_coords; //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
100 vector<Vec4> m_unitCoords; //!< Positive-only coordinates [0.0 .. 1.5].
101 vector<float> m_attribOne;
102 vector<Vec4> m_userAttribs[ShaderEvalContext::MAX_TEXTURES];
103 vector<deUint16> m_indices;
106 QuadGrid::QuadGrid (int gridSize, int width, int height, const Vec4& constCoords, const vector<Mat4>& userAttribTransforms
107 /*, const vector<TextureBinding>& textures*/)
108 : m_gridSize (gridSize)
109 , m_numVertices ((gridSize + 1) * (gridSize + 1))
110 , m_numTriangles (gridSize * gridSize * 2)
111 , m_constCoords (constCoords)
112 , m_userAttribTransforms (userAttribTransforms)
113 // , m_textures (textures)
115 Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f);
118 m_positions.resize(m_numVertices);
119 m_coords.resize(m_numVertices);
120 m_unitCoords.resize(m_numVertices);
121 m_attribOne.resize(m_numVertices);
122 m_screenPos.resize(m_numVertices);
125 for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++)
126 m_userAttribs[i].resize(m_numVertices);
128 for (int y = 0; y < gridSize+1; y++)
129 for (int x = 0; x < gridSize+1; x++)
131 float sx = (float)x / (float)gridSize;
132 float sy = (float)y / (float)gridSize;
133 float fx = 2.0f * sx - 1.0f;
134 float fy = 2.0f * sy - 1.0f;
135 int vtxNdx = ((y * (gridSize+1)) + x);
137 m_positions[vtxNdx] = Vec4(fx, fy, 0.0f, 1.0f);
138 m_attribOne[vtxNdx] = 1.0f;
139 m_screenPos[vtxNdx] = Vec4(sx, sy, 0.0f, 1.0f) * viewportScale;
140 m_coords[vtxNdx] = getCoords(sx, sy);
141 m_unitCoords[vtxNdx] = getUnitCoords(sx, sy);
143 for (int attribNdx = 0; attribNdx < getNumUserAttribs(); attribNdx++)
144 m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
148 m_indices.resize(3 * m_numTriangles);
149 for (int y = 0; y < gridSize; y++)
150 for (int x = 0; x < gridSize; x++)
152 int stride = gridSize + 1;
153 int v00 = (y * stride) + x;
154 int v01 = (y * stride) + x + 1;
155 int v10 = ((y+1) * stride) + x;
156 int v11 = ((y+1) * stride) + x + 1;
158 int baseNdx = ((y * gridSize) + x) * 6;
159 m_indices[baseNdx + 0] = (deUint16)v10;
160 m_indices[baseNdx + 1] = (deUint16)v00;
161 m_indices[baseNdx + 2] = (deUint16)v01;
163 m_indices[baseNdx + 3] = (deUint16)v10;
164 m_indices[baseNdx + 4] = (deUint16)v01;
165 m_indices[baseNdx + 5] = (deUint16)v11;
169 QuadGrid::~QuadGrid (void)
173 inline Vec4 QuadGrid::getCoords (float sx, float sy) const
175 float fx = 2.0f * sx - 1.0f;
176 float fy = 2.0f * sy - 1.0f;
177 return Vec4(fx, fy, -fx + 0.33f*fy, -0.275f*fx - fy);
180 inline Vec4 QuadGrid::getUnitCoords (float sx, float sy) const
182 return Vec4(sx, sy, 0.33f*sx + 0.5f*sy, 0.5f*sx + 0.25f*sy);
185 inline Vec4 QuadGrid::getUserAttrib (int attribNdx, float sx, float sy) const
187 // homogeneous normalized screen-space coordinates
188 return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f);
193 // ShaderEvalContext.
195 ShaderEvalContext::ShaderEvalContext (const QuadGrid& quadGrid_)
196 : constCoords(quadGrid_.getConstCoords())
198 , quadGrid(quadGrid_)
202 const vector<TextureBinding>& bindings = quadGrid.getTextures();
203 DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
205 // Fill in texture array.
206 for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
208 const TextureBinding& binding = bindings[ndx];
210 if (binding.getType() == TextureBinding::TYPE_NONE)
213 textures[ndx].sampler = binding.getSampler();
215 switch (binding.getType())
217 case TextureBinding::TYPE_2D: textures[ndx].tex2D = &binding.get2D()->getRefTexture(); break;
218 case TextureBinding::TYPE_CUBE_MAP: textures[ndx].texCube = &binding.getCube()->getRefTexture(); break;
219 case TextureBinding::TYPE_2D_ARRAY: textures[ndx].tex2DArray = &binding.get2DArray()->getRefTexture(); break;
220 case TextureBinding::TYPE_3D: textures[ndx].tex3D = &binding.get3D()->getRefTexture(); break;
228 ShaderEvalContext::~ShaderEvalContext (void)
232 void ShaderEvalContext::reset (float sx, float sy)
235 color = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
239 coords = quadGrid.getCoords(sx, sy);
240 unitCoords = quadGrid.getUnitCoords(sx, sy);
242 // Compute user attributes.
243 int numAttribs = quadGrid.getNumUserAttribs();
244 DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS);
245 for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++)
246 in[attribNdx] = quadGrid.getUserAttrib(attribNdx, sx, sy);
249 tcu::Vec4 ShaderEvalContext::texture2D (int unitNdx, const tcu::Vec2& texCoords)
251 // TODO: add texture binding
252 /* if (textures[unitNdx].tex2D)
253 return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f);
256 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
262 ShaderEvaluator::ShaderEvaluator (void)
263 : m_evalFunc(DE_NULL)
267 ShaderEvaluator::ShaderEvaluator (ShaderEvalFunc evalFunc)
268 : m_evalFunc(evalFunc)
272 ShaderEvaluator::~ShaderEvaluator (void)
276 void ShaderEvaluator::evaluate (ShaderEvalContext& ctx)
278 DE_ASSERT(m_evalFunc);
283 ShaderRenderCase::ShaderRenderCase (tcu::TestContext& testCtx,
285 const string& description,
287 ShaderEvalFunc evalFunc)
288 : vkt::TestCase(testCtx, name, description)
289 , m_isVertexCase(isVertexCase)
290 , m_evaluator(new ShaderEvaluator(evalFunc))
294 ShaderRenderCase::ShaderRenderCase (tcu::TestContext& testCtx,
296 const string& description,
298 ShaderEvaluator* evaluator)
299 : vkt::TestCase(testCtx, name, description)
300 , m_isVertexCase(isVertexCase)
301 , m_evaluator(evaluator)
305 ShaderRenderCase::~ShaderRenderCase (void)
309 void ShaderRenderCase::initPrograms (vk::ProgramCollection<glu::ProgramSources>& programCollection) const
311 if (!m_vertShaderSource.empty())
312 programCollection.add(m_name + "_vert") << glu::VertexSource(m_vertShaderSource);
314 if (!m_fragShaderSource.empty())
315 programCollection.add(m_name + "_frag") << glu::FragmentSource(m_fragShaderSource);
318 TestInstance* ShaderRenderCase::createInstance (Context& context) const
320 return new ShaderRenderCaseInstance(context, m_name, m_isVertexCase, *m_evaluator);
323 // ShaderRenderCaseInstance.
325 ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context& context, const string& name, bool isVertexCase, ShaderEvaluator& evaluator)
326 : vkt::TestInstance(context)
328 , m_isVertexCase(isVertexCase)
329 , m_evaluator(evaluator)
330 , m_clearColor(DEFAULT_CLEAR_COLOR)
331 , m_renderSize(100, 100)
332 , m_colorFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
336 ShaderRenderCaseInstance::~ShaderRenderCaseInstance (void)
340 tcu::TestStatus ShaderRenderCaseInstance::iterate (void)
343 IVec2 viewportSize = getViewportSize();
344 int width = viewportSize.x();
345 int height = viewportSize.y();
347 QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.125f, 0.25f, 0.5f, 1.0f), m_userAttribTransforms/*, m_textures*/);
350 Surface resImage(width, height);
351 render(resImage, quadGrid);
353 // Compute reference.
354 Surface refImage(width, height);
356 computeVertexReference(refImage, quadGrid);
358 computeFragmentReference(refImage, quadGrid);
360 //m_context.getTestContext().getLog() << TestLog::Image("Result", "Result", refImage.getAccess());
361 /*tcu::ConstPixelBufferAccess(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_renderSize.x(), m_renderSize.y(), 1, imagePtr)*/
364 bool compareOk = compareImages(resImage, refImage, 0.05f);
367 return tcu::TestStatus::pass("Result image matches reference");
369 return tcu::TestStatus::fail("Image mismatch");
372 void ShaderRenderCaseInstance::setupShaderData (void)
377 void ShaderRenderCaseInstance::setup (void)
382 void ShaderRenderCaseInstance::setupUniforms (const Vec4& constCoords)
385 DE_UNREF(constCoords);
388 tcu::IVec2 ShaderRenderCaseInstance::getViewportSize (void) const
390 return tcu::IVec2(de::min(m_renderSize.x(), MAX_RENDER_WIDTH),
391 de::min(m_renderSize.y(), MAX_RENDER_HEIGHT));
394 void ShaderRenderCaseInstance::setupDefaultInputs (void)
397 // SetupUniforms: map unifrom ids and set the values
400 void ShaderRenderCaseInstance::render (Surface& result, const QuadGrid& quadGrid)
402 // TODO!! Vk rendering
405 void ShaderRenderCaseInstance::computeVertexReference (Surface& result, const QuadGrid& quadGrid)
409 int width = result.getWidth();
410 int height = result.getHeight();
411 int gridSize = quadGrid.getGridSize();
412 int stride = gridSize + 1;
413 //bool hasAlpha = m_context.getRenderTarget().getPixelFormat().alphaBits > 0;
414 bool hasAlpha = true;
415 ShaderEvalContext evalCtx (quadGrid);
417 // Evaluate color for each vertex.
418 vector<Vec4> colors((gridSize+1)*(gridSize+1));
419 for (int y = 0; y < gridSize+1; y++)
420 for (int x = 0; x < gridSize+1; x++)
422 float sx = (float)x / (float)gridSize;
423 float sy = (float)y / (float)gridSize;
424 int vtxNdx = ((y * (gridSize+1)) + x);
426 evalCtx.reset(sx, sy);
427 m_evaluator.evaluate(evalCtx);
428 DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader.
429 Vec4 color = evalCtx.color;
434 colors[vtxNdx] = color;
438 for (int y = 0; y < gridSize; y++)
439 for (int x = 0; x < gridSize; x++)
441 float x0 = (float)x / (float)gridSize;
442 float x1 = (float)(x + 1) / (float)gridSize;
443 float y0 = (float)y / (float)gridSize;
444 float y1 = (float)(y + 1) / (float)gridSize;
446 float sx0 = x0 * (float)width;
447 float sx1 = x1 * (float)width;
448 float sy0 = y0 * (float)height;
449 float sy1 = y1 * (float)height;
450 float oosx = 1.0f / (sx1 - sx0);
451 float oosy = 1.0f / (sy1 - sy0);
453 int ix0 = deCeilFloatToInt32(sx0 - 0.5f);
454 int ix1 = deCeilFloatToInt32(sx1 - 0.5f);
455 int iy0 = deCeilFloatToInt32(sy0 - 0.5f);
456 int iy1 = deCeilFloatToInt32(sy1 - 0.5f);
458 int v00 = (y * stride) + x;
459 int v01 = (y * stride) + x + 1;
460 int v10 = ((y + 1) * stride) + x;
461 int v11 = ((y + 1) * stride) + x + 1;
462 Vec4 c00 = colors[v00];
463 Vec4 c01 = colors[v01];
464 Vec4 c10 = colors[v10];
465 Vec4 c11 = colors[v11];
467 //printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
469 for (int iy = iy0; iy < iy1; iy++)
470 for (int ix = ix0; ix < ix1; ix++)
472 DE_ASSERT(deInBounds32(ix, 0, width));
473 DE_ASSERT(deInBounds32(iy, 0, height));
475 float sfx = (float)ix + 0.5f;
476 float sfy = (float)iy + 0.5f;
477 float fx1 = deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f);
478 float fy1 = deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f);
480 // Triangle quad interpolation.
481 bool tri = fx1 + fy1 <= 1.0f;
482 float tx = tri ? fx1 : (1.0f-fx1);
483 float ty = tri ? fy1 : (1.0f-fy1);
484 const Vec4& t0 = tri ? c00 : c11;
485 const Vec4& t1 = tri ? c01 : c10;
486 const Vec4& t2 = tri ? c10 : c01;
487 Vec4 color = t0 + (t1-t0)*tx + (t2-t0)*ty;
489 result.setPixel(ix, iy, tcu::RGBA(color));
494 void ShaderRenderCaseInstance::computeFragmentReference (Surface& result, const QuadGrid& quadGrid)
497 int width = result.getWidth();
498 int height = result.getHeight();
499 //bool hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
500 bool hasAlpha = true;
501 ShaderEvalContext evalCtx (quadGrid);
504 for (int y = 0; y < height; y++)
505 for (int x = 0; x < width; x++)
507 float sx = ((float)x + 0.5f) / (float)width;
508 float sy = ((float)y + 0.5f) / (float)height;
510 evalCtx.reset(sx, sy);
511 m_evaluator.evaluate(evalCtx);
512 // Select either clear color or computed color based on discarded bit.
513 Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color;
518 result.setPixel(x, y, tcu::RGBA(color));
522 bool ShaderRenderCaseInstance::compareImages (const Surface& resImage, const Surface& refImage, float errorThreshold)
524 return tcu::fuzzyCompare(m_context.getTestContext().getLog(), "ComparisonResult", "Image comparison result", refImage, resImage, errorThreshold, tcu::COMPARE_LOG_RESULT);
528 } // shaderrendercase