Home | History | Annotate | Download | only in randomshaders
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Random Shader Generator
      3  * ----------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Program Executor.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "rsgProgramExecutor.hpp"
     25 #include "rsgExecutionContext.hpp"
     26 #include "rsgVariableValue.hpp"
     27 #include "rsgUtils.hpp"
     28 #include "tcuSurface.hpp"
     29 #include "deMath.h"
     30 #include "deString.h"
     31 
     32 #include <set>
     33 #include <string>
     34 #include <map>
     35 
     36 using std::set;
     37 using std::string;
     38 using std::vector;
     39 using std::map;
     40 
     41 namespace rsg
     42 {
     43 
     44 class VaryingStorage
     45 {
     46 public:
     47 							VaryingStorage		(const VariableType& type, int numVertices);
     48 							~VaryingStorage		(void) {}
     49 
     50 	ValueAccess				getValue			(const VariableType& type, int vtxNdx);
     51 	ConstValueAccess		getValue			(const VariableType& type, int vtxNdx) const;
     52 
     53 private:
     54 	std::vector<Scalar>		m_value;
     55 };
     56 
     57 VaryingStorage::VaryingStorage (const VariableType& type, int numVertices)
     58 	: m_value(type.getScalarSize()*numVertices)
     59 {
     60 }
     61 
     62 ValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx)
     63 {
     64 	return ValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
     65 }
     66 
     67 ConstValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx) const
     68 {
     69 	return ConstValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
     70 }
     71 
     72 class VaryingStore
     73 {
     74 public:
     75 							VaryingStore		(int numVertices);
     76 							~VaryingStore		(void);
     77 
     78 	VaryingStorage*			getStorage			(const VariableType& type, const char* name);
     79 
     80 private:
     81 	int											m_numVertices;
     82 	std::map<std::string, VaryingStorage*>		m_values;
     83 };
     84 
     85 VaryingStore::VaryingStore (int numVertices)
     86 	: m_numVertices(numVertices)
     87 {
     88 }
     89 
     90 VaryingStore::~VaryingStore (void)
     91 {
     92 	for (map<string, VaryingStorage*>::iterator i = m_values.begin(); i != m_values.end(); i++)
     93 		delete i->second;
     94 	m_values.clear();
     95 }
     96 
     97 VaryingStorage* VaryingStore::getStorage (const VariableType& type, const char* name)
     98 {
     99 	VaryingStorage* storage = m_values[name];
    100 
    101 	if (!storage)
    102 	{
    103 		storage = new VaryingStorage(type, m_numVertices);
    104 		m_values[name] = storage;
    105 	}
    106 
    107 	return storage;
    108 }
    109 
    110 inline float interpolateVertexQuad (const tcu::Vec4& quad, float x, float y)
    111 {
    112 	float w00 = (1.0f-x)*(1.0f-y);
    113 	float w01 = (1.0f-x)*y;
    114 	float w10 = x*(1.0f-y);
    115 	float w11 = x*y;
    116 	return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
    117 }
    118 
    119 inline float interpolateVertex (float x0y0, float x1y1, float x, float y)
    120 {
    121 	return interpolateVertexQuad(tcu::Vec4(x0y0, (x0y0+x1y1)*0.5f, (x0y0+x1y1)*0.5f, x1y1), x, y);
    122 }
    123 
    124 inline float interpolateTri (float v0, float v1, float v2, float x, float y)
    125 {
    126 	return v0 + (v1-v0)*x + (v2-v0)*y;
    127 }
    128 
    129 inline float interpolateFragment (const tcu::Vec4& quad, float x, float y)
    130 {
    131 	if (x + y < 1.0f)
    132 		return interpolateTri(quad.x(), quad.y(), quad.z(), x, y);
    133 	else
    134 		return interpolateTri(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
    135 }
    136 
    137 template <int Stride>
    138 void interpolateVertexInput (StridedValueAccess<Stride> dst, int dstComp, const ConstValueRangeAccess valueRange, float x, float y)
    139 {
    140 	TCU_CHECK(valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT);
    141 	int numElements = valueRange.getType().getNumElements();
    142 	for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
    143 	{
    144 		float xd, yd;
    145 		getVertexInterpolationCoords(xd, yd, x, y, elementNdx);
    146 		dst.component(elementNdx).asFloat(dstComp) = interpolateVertex(valueRange.getMin().component(elementNdx).asFloat(), valueRange.getMax().component(elementNdx).asFloat(), xd, yd);
    147 	}
    148 }
    149 
    150 template <int Stride>
    151 void interpolateFragmentInput (StridedValueAccess<Stride> dst, int dstComp, ConstValueAccess vtx0, ConstValueAccess vtx1, ConstValueAccess vtx2, ConstValueAccess vtx3, float x, float y)
    152 {
    153 	TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
    154 	int numElements = dst.getType().getNumElements();
    155 	for (int ndx = 0; ndx < numElements; ndx++)
    156 		dst.component(ndx).asFloat(dstComp) = interpolateFragment(tcu::Vec4(vtx0.component(ndx).asFloat(), vtx1.component(ndx).asFloat(), vtx2.component(ndx).asFloat(), vtx3.component(ndx).asFloat()), x, y);
    157 }
    158 
    159 template <int Stride>
    160 void copyVarying (ValueAccess dst, ConstStridedValueAccess<Stride> src, int compNdx)
    161 {
    162 	TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
    163 	for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
    164 		dst.component(elemNdx).asFloat() = src.component(elemNdx).asFloat(compNdx);
    165 }
    166 
    167 ProgramExecutor::ProgramExecutor (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight)
    168 	: m_dst			(dst)
    169 	, m_gridWidth	(gridWidth)
    170 	, m_gridHeight	(gridHeight)
    171 {
    172 }
    173 
    174 ProgramExecutor::~ProgramExecutor (void)
    175 {
    176 }
    177 
    178 void ProgramExecutor::setTexture (int samplerNdx, const tcu::Texture2D* texture, const tcu::Sampler& sampler)
    179 {
    180 	m_samplers2D[samplerNdx] = Sampler2D(texture, sampler);
    181 }
    182 
    183 void ProgramExecutor::setTexture (int samplerNdx, const tcu::TextureCube* texture, const tcu::Sampler& sampler)
    184 {
    185 	m_samplersCube[samplerNdx] = SamplerCube(texture, sampler);
    186 }
    187 
    188 inline tcu::IVec4 computeVertexIndices (float cellWidth, float cellHeight, int gridVtxWidth, int gridVtxHeight, int x, int y)
    189 {
    190 	DE_UNREF(gridVtxHeight);
    191 	int x0 = (int)deFloatFloor((float)x / cellWidth);
    192 	int y0 = (int)deFloatFloor((float)y / cellHeight);
    193 	return tcu::IVec4(y0*gridVtxWidth + x0, y0*gridVtxWidth + x0 + 1, (y0+1)*gridVtxWidth + x0, (y0+1)*gridVtxWidth + x0 + 1);
    194 }
    195 
    196 inline tcu::Vec2 computeGridCellWeights (float cellWidth, float cellHeight, int x, int y)
    197 {
    198 	float gx = ((float)x + 0.5f) / cellWidth;
    199 	float gy = ((float)y + 0.5f) / cellHeight;
    200 	return tcu::Vec2(deFloatFrac(gx), deFloatFrac(gy));
    201 }
    202 
    203 inline tcu::RGBA toColor (tcu::Vec4 rgba)
    204 {
    205 	return tcu::RGBA(deClamp32(deRoundFloatToInt32(rgba.x()*255), 0, 255),
    206 					 deClamp32(deRoundFloatToInt32(rgba.y()*255), 0, 255),
    207 					 deClamp32(deRoundFloatToInt32(rgba.z()*255), 0, 255),
    208 					 deClamp32(deRoundFloatToInt32(rgba.w()*255), 0, 255));
    209 }
    210 
    211 void ProgramExecutor::execute (const Shader& vertexShader, const Shader& fragmentShader, const vector<VariableValue>& uniformValues)
    212 {
    213 	int	gridVtxWidth	= m_gridWidth+1;
    214 	int gridVtxHeight	= m_gridHeight+1;
    215 	int numVertices		= gridVtxWidth*gridVtxHeight;
    216 
    217 	VaryingStore varyingStore(numVertices);
    218 
    219 	// Execute vertex shader
    220 	{
    221 		ExecutionContext	execCtx(m_samplers2D, m_samplersCube);
    222 		int					numPackets	= numVertices + ((numVertices%EXEC_VEC_WIDTH) ? 1 : 0);
    223 
    224 		const vector<ShaderInput*>& inputs	= vertexShader.getInputs();
    225 		vector<const Variable*>		outputs;
    226 		vertexShader.getOutputs(outputs);
    227 
    228 		// Set uniform values
    229 		for (vector<VariableValue>::const_iterator uniformIter = uniformValues.begin(); uniformIter != uniformValues.end(); uniformIter++)
    230 			execCtx.getValue(uniformIter->getVariable()) = uniformIter->getValue().value();
    231 
    232 		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
    233 		{
    234 			int packetStart	= packetNdx*EXEC_VEC_WIDTH;
    235 			int packetEnd	= deMin32((packetNdx+1)*EXEC_VEC_WIDTH, numVertices);
    236 
    237 			// Compute values for vertex shader inputs
    238 			for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
    239 			{
    240 				const ShaderInput*	input	= *i;
    241 				ExecValueAccess		access	= execCtx.getValue(input->getVariable());
    242 
    243 				for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
    244 				{
    245 					int		y	= (vtxNdx/gridVtxWidth);
    246 					int		x	= vtxNdx - y*gridVtxWidth;
    247 					float	xf	= (float)x / (float)(gridVtxWidth-1);
    248 					float	yf	= (float)y / (float)(gridVtxHeight-1);
    249 
    250 					interpolateVertexInput(access, vtxNdx-packetStart, input->getValueRange(), xf, yf);
    251 				}
    252 			}
    253 
    254 			// Execute vertex shader for packet
    255 			vertexShader.execute(execCtx);
    256 
    257 			// Store output values
    258 			for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
    259 			{
    260 				const Variable*			output	= *i;
    261 
    262 				if (deStringEqual(output->getName(), "gl_Position"))
    263 					continue; // Do not store position
    264 
    265 				ExecConstValueAccess	access	= execCtx.getValue(output);
    266 				VaryingStorage*			dst		= varyingStore.getStorage(output->getType(), output->getName());
    267 
    268 				for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
    269 				{
    270 					ValueAccess varyingAccess = dst->getValue(output->getType(), vtxNdx);
    271 					copyVarying(varyingAccess, access, vtxNdx-packetStart);
    272 				}
    273 			}
    274 		}
    275 	}
    276 
    277 	// Execute fragment shader
    278 	{
    279 		ExecutionContext execCtx(m_samplers2D, m_samplersCube);
    280 
    281 		// Assign uniform values
    282 		for (vector<VariableValue>::const_iterator i = uniformValues.begin(); i != uniformValues.end(); i++)
    283 			execCtx.getValue(i->getVariable()) = i->getValue().value();
    284 
    285 		const vector<ShaderInput*>& inputs			= fragmentShader.getInputs();
    286 		const Variable*				fragColorVar	= DE_NULL;
    287 		vector<const Variable*>		outputs;
    288 
    289 		// Find fragment shader output assigned to location 0. This is fragment color.
    290 		fragmentShader.getOutputs(outputs);
    291 		for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
    292 		{
    293 			if ((*i)->getLayoutLocation() == 0)
    294 			{
    295 				fragColorVar = *i;
    296 				break;
    297 			}
    298 		}
    299 		TCU_CHECK(fragColorVar);
    300 
    301 		int	width		= m_dst.getWidth();
    302 		int height		= m_dst.getHeight();
    303 		int numPackets	= (width*height)/EXEC_VEC_WIDTH + (((width*height)%EXEC_VEC_WIDTH) ? 1 : 0);
    304 
    305 		float cellWidth		= (float)width	/ (float)m_gridWidth;
    306 		float cellHeight	= (float)height	/ (float)m_gridHeight;
    307 
    308 		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
    309 		{
    310 			int packetStart	= packetNdx*EXEC_VEC_WIDTH;
    311 			int packetEnd	= deMin32((packetNdx+1)*EXEC_VEC_WIDTH, width*height);
    312 
    313 			// Interpolate varyings
    314 			for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
    315 			{
    316 				const ShaderInput*		input	= *i;
    317 				ExecValueAccess			access	= execCtx.getValue(input->getVariable());
    318 				const VariableType&		type	= input->getVariable()->getType();
    319 				const VaryingStorage*	src		= varyingStore.getStorage(type, input->getVariable()->getName());
    320 
    321 				// \todo [2011-03-08 pyry] Part of this could be pre-computed...
    322 				for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
    323 				{
    324 					int y = fragNdx/width;
    325 					int x = fragNdx - y*width;
    326 					tcu::IVec4	vtxIndices	= computeVertexIndices(cellWidth, cellHeight, gridVtxWidth, gridVtxHeight, x, y);
    327 					tcu::Vec2	weights		= computeGridCellWeights(cellWidth, cellHeight, x, y);
    328 
    329 					interpolateFragmentInput(access, fragNdx-packetStart,
    330 											 src->getValue(type, vtxIndices.x()),
    331 											 src->getValue(type, vtxIndices.y()),
    332 											 src->getValue(type, vtxIndices.z()),
    333 											 src->getValue(type, vtxIndices.w()),
    334 											 weights.x(), weights.y());
    335 				}
    336 			}
    337 
    338 			// Execute fragment shader
    339 			fragmentShader.execute(execCtx);
    340 
    341 			// Write resulting color
    342 			ExecConstValueAccess colorValue = execCtx.getValue(fragColorVar);
    343 			for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
    344 			{
    345 				int			y		= fragNdx/width;
    346 				int			x		= fragNdx - y*width;
    347 				int			cNdx	= fragNdx-packetStart;
    348 				tcu::Vec4	c		= tcu::Vec4(colorValue.component(0).asFloat(cNdx),
    349 												colorValue.component(1).asFloat(cNdx),
    350 												colorValue.component(2).asFloat(cNdx),
    351 												colorValue.component(3).asFloat(cNdx));
    352 
    353 				// \todo [2012-11-13 pyry] Reverse order.
    354 				m_dst.setPixel(c, x, m_dst.getHeight()-y-1);
    355 			}
    356 		}
    357 	}
    358 }
    359 
    360 } // rsg
    361