ShaderRenderCase: Add basic reference drawing
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / shaderrendercase / vktShaderRenderCase.cpp
1 /*------------------------------------------------------------------------
2  * Copyright (c) 2015 The Khronos Group Inc.
3  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4  *
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:
12  *
13  * The above copyright notice(s) and this permission notice shall be included
14  * in all copies or substantial portions of the Materials.
15  *
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.
19  *
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.
27  *
28  *//*!
29  * \file
30  * \brief Vulkan ShaderRenderCase
31  *//*--------------------------------------------------------------------*/
32
33 #include "vktShaderRenderCase.hpp"
34
35 #include "tcuImageCompare.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuVector.hpp"
38 #include "tcuTestLog.hpp"
39
40 #include "deMath.h"
41
42 #include <vector>
43 #include <string>
44
45 namespace vkt
46 {
47 namespace shaderrendercase
48 {
49
50 using namespace std;
51 using namespace tcu;
52
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);
57
58 // QuadGrid.
59
60 class QuadGrid
61 {
62 public:
63                             QuadGrid                (int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords, const vector<Mat4>& userAttribTransforms
64 /*, const vector<TextureBinding>& textures*/);
65                             ~QuadGrid               (void);
66
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; }
72         // TODO:
73     //const vector<TextureBinding>&   getTextures     (void) const { return m_textures; }
74
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]; }
81
82     Vec4                    getCoords               (float sx, float sy) const;
83     Vec4                    getUnitCoords           (float sx, float sy) const;
84
85     int                     getNumUserAttribs       (void) const { return (int)m_userAttribTransforms.size(); }
86     Vec4                    getUserAttrib           (int attribNdx, float sx, float sy) const;
87
88 private:
89     int                     m_gridSize;
90     int                     m_numVertices;
91     int                     m_numTriangles;
92     Vec4                    m_constCoords;
93     vector<Mat4>            m_userAttribTransforms;
94         // TODO:
95     // vector<TextureBinding>  m_textures;
96
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;
104 };
105
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)
114 {
115     Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f);
116
117     // Compute vertices.
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);
123
124     // User attributes.
125     for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++)
126         m_userAttribs[i].resize(m_numVertices);
127
128     for (int y = 0; y < gridSize+1; y++)
129     for (int x = 0; x < gridSize+1; x++)
130     {
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);
136
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);
142
143         for (int attribNdx = 0; attribNdx < getNumUserAttribs(); attribNdx++)
144             m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
145     }
146
147     // Compute indices.
148     m_indices.resize(3 * m_numTriangles);
149     for (int y = 0; y < gridSize; y++)
150     for (int x = 0; x < gridSize; x++)
151     {
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;
157
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;
162
163         m_indices[baseNdx + 3] = (deUint16)v10;
164         m_indices[baseNdx + 4] = (deUint16)v01;
165         m_indices[baseNdx + 5] = (deUint16)v11;
166     }
167 }
168
169 QuadGrid::~QuadGrid (void)
170 {
171 }
172
173 inline Vec4 QuadGrid::getCoords (float sx, float sy) const
174 {
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);
178 }
179
180 inline Vec4 QuadGrid::getUnitCoords (float sx, float sy) const
181 {
182     return Vec4(sx, sy, 0.33f*sx + 0.5f*sy, 0.5f*sx + 0.25f*sy);
183 }
184
185 inline Vec4 QuadGrid::getUserAttrib (int attribNdx, float sx, float sy) const
186 {
187     // homogeneous normalized screen-space coordinates
188     return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f);
189 }
190
191
192
193 // ShaderEvalContext.
194
195 ShaderEvalContext::ShaderEvalContext (const QuadGrid& quadGrid_)
196         : constCoords(quadGrid_.getConstCoords())
197         , isDiscarded(false)
198         , quadGrid(quadGrid_)
199 {
200         // TODO...
201 /*
202     const vector<TextureBinding>& bindings = quadGrid.getTextures();
203     DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
204
205     // Fill in texture array.
206     for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
207     {
208         const TextureBinding& binding = bindings[ndx];
209
210         if (binding.getType() == TextureBinding::TYPE_NONE)
211             continue;
212
213         textures[ndx].sampler = binding.getSampler();
214
215         switch (binding.getType())
216         {
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;
221             default:
222                 DE_ASSERT(DE_FALSE);
223         }
224     }
225 */
226 }
227
228 ShaderEvalContext::~ShaderEvalContext (void)
229 {
230 }
231
232 void ShaderEvalContext::reset (float sx, float sy)
233 {
234     // Clear old values
235     color       = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
236     isDiscarded = false;
237
238     // Compute coords
239     coords      = quadGrid.getCoords(sx, sy);
240     unitCoords  = quadGrid.getUnitCoords(sx, sy);
241
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);
247 }
248
249 tcu::Vec4 ShaderEvalContext::texture2D (int unitNdx, const tcu::Vec2& texCoords)
250 {
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);
254     else
255 */
256         return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
257 }
258
259
260 // ShaderEvaluator.
261
262 ShaderEvaluator::ShaderEvaluator (void)
263     : m_evalFunc(DE_NULL)
264 {
265 }
266
267 ShaderEvaluator::ShaderEvaluator (ShaderEvalFunc evalFunc)
268     : m_evalFunc(evalFunc)
269 {
270 }
271
272 ShaderEvaluator::~ShaderEvaluator (void)
273 {
274 }
275
276 void ShaderEvaluator::evaluate (ShaderEvalContext& ctx)
277 {
278     DE_ASSERT(m_evalFunc);
279     m_evalFunc(ctx);
280 }
281
282 // ShaderRenderCase
283 ShaderRenderCase::ShaderRenderCase      (tcu::TestContext& testCtx,
284                                                                         const string& name,
285                                                                         const string& description,
286                                                                         bool isVertexCase,
287                                                                         ShaderEvalFunc evalFunc)
288         : vkt::TestCase(testCtx, name, description)
289         , m_isVertexCase(isVertexCase)
290         , m_evaluator(new ShaderEvaluator(evalFunc))
291 {
292 }
293
294 ShaderRenderCase::ShaderRenderCase      (tcu::TestContext& testCtx,
295                                                                         const string& name,
296                                                                         const string& description,
297                                                                         bool isVertexCase,
298                                                                         ShaderEvaluator* evaluator)
299         : vkt::TestCase(testCtx, name, description)
300         , m_isVertexCase(isVertexCase)
301         , m_evaluator(evaluator)
302 {
303 }
304
305 ShaderRenderCase::~ShaderRenderCase (void)
306 {
307 }
308
309 void ShaderRenderCase::initPrograms (vk::ProgramCollection<glu::ProgramSources>& programCollection) const
310 {
311         if (!m_vertShaderSource.empty())
312                 programCollection.add(m_name + "_vert") << glu::VertexSource(m_vertShaderSource);
313
314         if (!m_fragShaderSource.empty())
315                 programCollection.add(m_name + "_frag") << glu::FragmentSource(m_fragShaderSource);
316 }
317
318 TestInstance* ShaderRenderCase::createInstance (Context& context) const
319 {
320         return new ShaderRenderCaseInstance(context, m_name, m_isVertexCase, *m_evaluator);
321 }
322
323 // ShaderRenderCaseInstance.
324
325 ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context& context, const string& name, bool isVertexCase, ShaderEvaluator& evaluator)
326         : vkt::TestInstance(context)
327         , m_name(name)
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)
333 {
334 }
335
336 ShaderRenderCaseInstance::~ShaderRenderCaseInstance (void)
337 {
338 }
339
340 tcu::TestStatus ShaderRenderCaseInstance::iterate (void)
341 {
342         // Create quad grid.
343         IVec2   viewportSize    = getViewportSize();
344         int             width                   = viewportSize.x();
345         int     height                  = viewportSize.y();
346
347         QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.125f, 0.25f, 0.5f, 1.0f), m_userAttribTransforms/*, m_textures*/);
348
349         // Render result.
350         Surface resImage(width, height);
351         render(resImage, quadGrid);
352
353         // Compute reference.
354         Surface refImage(width, height);
355         if (m_isVertexCase)
356                 computeVertexReference(refImage, quadGrid);
357         else
358                 computeFragmentReference(refImage, quadGrid);
359
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)*/
362
363         // Compare.
364         bool compareOk = compareImages(resImage, refImage, 0.05f);
365
366         if (compareOk)
367                 return tcu::TestStatus::pass("Result image matches reference");
368         else
369                 return tcu::TestStatus::fail("Image mismatch");
370 }
371
372 void ShaderRenderCaseInstance::setupShaderData (void)
373 {
374         // TODO!!!
375 }
376
377 void ShaderRenderCaseInstance::setup (void)
378 {
379         // TODO!!
380 }
381
382 void ShaderRenderCaseInstance::setupUniforms (const Vec4& constCoords)
383 {
384         // TODO!!
385         DE_UNREF(constCoords);
386 }
387
388 tcu::IVec2 ShaderRenderCaseInstance::getViewportSize (void) const
389 {
390         return tcu::IVec2(de::min(m_renderSize.x(), MAX_RENDER_WIDTH),
391                                           de::min(m_renderSize.y(), MAX_RENDER_HEIGHT));
392 }
393
394 void ShaderRenderCaseInstance::setupDefaultInputs (void)
395 {
396         // TODO!!
397         // SetupUniforms: map unifrom ids and set the values
398 }
399
400 void ShaderRenderCaseInstance::render (Surface& result, const QuadGrid& quadGrid)
401 {
402         // TODO!! Vk rendering
403 }
404
405 void ShaderRenderCaseInstance::computeVertexReference (Surface& result, const QuadGrid& quadGrid)
406 {
407         // TODO!!
408         // Buffer info.
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);
416
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++)
421         {
422                 float                           sx                      = (float)x / (float)gridSize;
423                 float                           sy                      = (float)y / (float)gridSize;
424                 int                                     vtxNdx          = ((y * (gridSize+1)) + x);
425
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;
430
431                 if (!hasAlpha)
432                         color.w() = 1.0f;
433
434                 colors[vtxNdx] = color;
435         }
436
437         // Render quads.
438         for (int y = 0; y < gridSize; y++)
439         for (int x = 0; x < gridSize; x++)
440         {
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;
445
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);
452
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);
457
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];
466
467                 //printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
468
469                 for (int iy = iy0; iy < iy1; iy++)
470                 for (int ix = ix0; ix < ix1; ix++)
471                 {
472                         DE_ASSERT(deInBounds32(ix, 0, width));
473                         DE_ASSERT(deInBounds32(iy, 0, height));
474
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);
479
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;
488
489                         result.setPixel(ix, iy, tcu::RGBA(color));
490                 }
491         }
492 }
493
494 void ShaderRenderCaseInstance::computeFragmentReference (Surface& result, const QuadGrid& quadGrid)
495 {
496     // Buffer info.
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);
502
503         // Render.
504         for (int y = 0; y < height; y++)
505         for (int x = 0; x < width; x++)
506         {
507                 float sx = ((float)x + 0.5f) / (float)width;
508                 float sy = ((float)y + 0.5f) / (float)height;
509
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;
514
515                 if (!hasAlpha)
516                         color.w() = 1.0f;
517
518                 result.setPixel(x, y, tcu::RGBA(color));
519         }
520 }
521
522 bool ShaderRenderCaseInstance::compareImages (const Surface& resImage, const Surface& refImage, float errorThreshold)
523 {
524         return tcu::fuzzyCompare(m_context.getTestContext().getLog(), "ComparisonResult", "Image comparison result", refImage, resImage, errorThreshold, tcu::COMPARE_LOG_RESULT);
525 }
526
527
528 } // shaderrendercase
529 } // vkt