1// Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Shader.cpp: Implements the Shader class and its derived classes 16// VertexShader and FragmentShader. Implements GL shader objects and related 17// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. 18 19#include "Shader.h" 20 21#include "main.h" 22#include "utilities.h" 23 24#include <string> 25#include <algorithm> 26 27namespace es2 28{ 29bool Shader::compilerInitialized = false; 30 31Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager) 32{ 33 mSource = nullptr; 34 35 clear(); 36 37 mRefCount = 0; 38 mDeleteStatus = false; 39} 40 41Shader::~Shader() 42{ 43 delete[] mSource; 44} 45 46GLuint Shader::getName() const 47{ 48 return mHandle; 49} 50 51void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) 52{ 53 delete[] mSource; 54 int totalLength = 0; 55 56 for(int i = 0; i < count; i++) 57 { 58 if(length && length[i] >= 0) 59 { 60 totalLength += length[i]; 61 } 62 else 63 { 64 totalLength += (int)strlen(string[i]); 65 } 66 } 67 68 mSource = new char[totalLength + 1]; 69 char *code = mSource; 70 71 for(int i = 0; i < count; i++) 72 { 73 int stringLength; 74 75 if(length && length[i] >= 0) 76 { 77 stringLength = length[i]; 78 } 79 else 80 { 81 stringLength = (int)strlen(string[i]); 82 } 83 84 strncpy(code, string[i], stringLength); 85 code += stringLength; 86 } 87 88 mSource[totalLength] = '\0'; 89} 90 91size_t Shader::getInfoLogLength() const 92{ 93 if(infoLog.empty()) 94 { 95 return 0; 96 } 97 else 98 { 99 return infoLog.size() + 1; 100 } 101} 102 103void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLogOut) 104{ 105 int index = 0; 106 107 if(bufSize > 0) 108 { 109 if(!infoLog.empty()) 110 { 111 index = std::min(bufSize - 1, (GLsizei)infoLog.size()); 112 memcpy(infoLogOut, infoLog.c_str(), index); 113 } 114 115 infoLogOut[index] = '\0'; 116 } 117 118 if(length) 119 { 120 *length = index; 121 } 122} 123 124size_t Shader::getSourceLength() const 125{ 126 if(!mSource) 127 { 128 return 0; 129 } 130 else 131 { 132 return strlen(mSource) + 1; 133 } 134} 135 136void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) 137{ 138 int index = 0; 139 140 if(bufSize > 0) 141 { 142 if(mSource) 143 { 144 index = std::min(bufSize - 1, (int)strlen(mSource)); 145 memcpy(source, mSource, index); 146 } 147 148 source[index] = '\0'; 149 } 150 151 if(length) 152 { 153 *length = index; 154 } 155} 156 157TranslatorASM *Shader::createCompiler(GLenum shaderType) 158{ 159 if(!compilerInitialized) 160 { 161 InitCompilerGlobals(); 162 compilerInitialized = true; 163 } 164 165 TranslatorASM *assembler = new TranslatorASM(this, shaderType); 166 167 ShBuiltInResources resources; 168 resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; 169 resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; 170 resources.MaxVaryingVectors = MAX_VARYING_VECTORS; 171 resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; 172 resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; 173 resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; 174 resources.MaxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS; 175 resources.MaxDrawBuffers = MAX_DRAW_BUFFERS; 176 resources.MaxVertexOutputVectors = MAX_VERTEX_OUTPUT_VECTORS; 177 resources.MaxFragmentInputVectors = MAX_FRAGMENT_INPUT_VECTORS; 178 resources.MinProgramTexelOffset = MIN_PROGRAM_TEXEL_OFFSET; 179 resources.MaxProgramTexelOffset = MAX_PROGRAM_TEXEL_OFFSET; 180 resources.OES_standard_derivatives = 1; 181 resources.OES_fragment_precision_high = 1; 182 resources.OES_EGL_image_external = 1; 183 resources.EXT_draw_buffers = 1; 184 resources.ARB_texture_rectangle = 1; 185 resources.MaxCallStackDepth = 64; 186 assembler->Init(resources); 187 188 return assembler; 189} 190 191void Shader::clear() 192{ 193 infoLog.clear(); 194 195 varyings.clear(); 196 activeUniforms.clear(); 197 activeAttributes.clear(); 198} 199 200void Shader::compile() 201{ 202 clear(); 203 204 createShader(); 205 TranslatorASM *compiler = createCompiler(getType()); 206 207 // Ensure we don't pass a nullptr source to the compiler 208 const char *source = "\0"; 209 if(mSource) 210 { 211 source = mSource; 212 } 213 214 bool success = compiler->compile(&source, 1, SH_OBJECT_CODE); 215 216 if(false) 217 { 218 static int serial = 1; 219 220 if(false) 221 { 222 char buffer[256]; 223 sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial); 224 FILE *file = fopen(buffer, "wt"); 225 fprintf(file, "%s", mSource); 226 fclose(file); 227 } 228 229 getShader()->print("shader-output-%d-%d.txt", getName(), serial); 230 231 serial++; 232 } 233 234 shaderVersion = compiler->getShaderVersion(); 235 int clientVersion = es2::getContext()->getClientVersion(); 236 237 if(shaderVersion >= 300 && clientVersion < 3) 238 { 239 infoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts"; 240 success = false; 241 } 242 243 if(!success) 244 { 245 deleteShader(); 246 247 infoLog += compiler->getInfoSink().info.c_str(); 248 TRACE("\n%s", infoLog.c_str()); 249 } 250 251 delete compiler; 252} 253 254bool Shader::isCompiled() 255{ 256 return getShader() != 0; 257} 258 259void Shader::addRef() 260{ 261 mRefCount++; 262} 263 264void Shader::release() 265{ 266 mRefCount--; 267 268 if(mRefCount == 0 && mDeleteStatus) 269 { 270 mResourceManager->deleteShader(mHandle); 271 } 272} 273 274unsigned int Shader::getRefCount() const 275{ 276 return mRefCount; 277} 278 279bool Shader::isFlaggedForDeletion() const 280{ 281 return mDeleteStatus; 282} 283 284void Shader::flagForDeletion() 285{ 286 mDeleteStatus = true; 287} 288 289void Shader::releaseCompiler() 290{ 291 FreeCompilerGlobals(); 292 compilerInitialized = false; 293} 294 295// true if varying x has a higher priority in packing than y 296bool Shader::compareVarying(const glsl::Varying &x, const glsl::Varying &y) 297{ 298 if(x.type == y.type) 299 { 300 return x.size() > y.size(); 301 } 302 303 switch(x.type) 304 { 305 case GL_FLOAT_MAT4: return true; 306 case GL_FLOAT_MAT2: 307 switch(y.type) 308 { 309 case GL_FLOAT_MAT4: return false; 310 case GL_FLOAT_MAT2: return true; 311 case GL_FLOAT_VEC4: return true; 312 case GL_FLOAT_MAT3: return true; 313 case GL_FLOAT_VEC3: return true; 314 case GL_FLOAT_VEC2: return true; 315 case GL_FLOAT: return true; 316 default: UNREACHABLE(y.type); 317 } 318 break; 319 case GL_FLOAT_VEC4: 320 switch(y.type) 321 { 322 case GL_FLOAT_MAT4: return false; 323 case GL_FLOAT_MAT2: return false; 324 case GL_FLOAT_VEC4: return true; 325 case GL_FLOAT_MAT3: return true; 326 case GL_FLOAT_VEC3: return true; 327 case GL_FLOAT_VEC2: return true; 328 case GL_FLOAT: return true; 329 default: UNREACHABLE(y.type); 330 } 331 break; 332 case GL_FLOAT_MAT3: 333 switch(y.type) 334 { 335 case GL_FLOAT_MAT4: return false; 336 case GL_FLOAT_MAT2: return false; 337 case GL_FLOAT_VEC4: return false; 338 case GL_FLOAT_MAT3: return true; 339 case GL_FLOAT_VEC3: return true; 340 case GL_FLOAT_VEC2: return true; 341 case GL_FLOAT: return true; 342 default: UNREACHABLE(y.type); 343 } 344 break; 345 case GL_FLOAT_VEC3: 346 switch(y.type) 347 { 348 case GL_FLOAT_MAT4: return false; 349 case GL_FLOAT_MAT2: return false; 350 case GL_FLOAT_VEC4: return false; 351 case GL_FLOAT_MAT3: return false; 352 case GL_FLOAT_VEC3: return true; 353 case GL_FLOAT_VEC2: return true; 354 case GL_FLOAT: return true; 355 default: UNREACHABLE(y.type); 356 } 357 break; 358 case GL_FLOAT_VEC2: 359 switch(y.type) 360 { 361 case GL_FLOAT_MAT4: return false; 362 case GL_FLOAT_MAT2: return false; 363 case GL_FLOAT_VEC4: return false; 364 case GL_FLOAT_MAT3: return false; 365 case GL_FLOAT_VEC3: return false; 366 case GL_FLOAT_VEC2: return true; 367 case GL_FLOAT: return true; 368 default: UNREACHABLE(y.type); 369 } 370 break; 371 case GL_FLOAT: return false; 372 default: UNREACHABLE(x.type); 373 } 374 375 return false; 376} 377 378VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 379{ 380 vertexShader = 0; 381} 382 383VertexShader::~VertexShader() 384{ 385 delete vertexShader; 386} 387 388GLenum VertexShader::getType() const 389{ 390 return GL_VERTEX_SHADER; 391} 392 393int VertexShader::getSemanticIndex(const std::string &attributeName) const 394{ 395 if(!attributeName.empty()) 396 { 397 for(const auto &attribute : activeAttributes) 398 { 399 if(attribute.name == attributeName) 400 { 401 return attribute.registerIndex; 402 } 403 } 404 } 405 406 return -1; 407} 408 409sw::Shader *VertexShader::getShader() const 410{ 411 return vertexShader; 412} 413 414sw::VertexShader *VertexShader::getVertexShader() const 415{ 416 return vertexShader; 417} 418 419void VertexShader::createShader() 420{ 421 delete vertexShader; 422 vertexShader = new sw::VertexShader(); 423} 424 425void VertexShader::deleteShader() 426{ 427 delete vertexShader; 428 vertexShader = nullptr; 429} 430 431FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) 432{ 433 pixelShader = 0; 434} 435 436FragmentShader::~FragmentShader() 437{ 438 delete pixelShader; 439} 440 441GLenum FragmentShader::getType() const 442{ 443 return GL_FRAGMENT_SHADER; 444} 445 446sw::Shader *FragmentShader::getShader() const 447{ 448 return pixelShader; 449} 450 451sw::PixelShader *FragmentShader::getPixelShader() const 452{ 453 return pixelShader; 454} 455 456void FragmentShader::createShader() 457{ 458 delete pixelShader; 459 pixelShader = new sw::PixelShader(); 460} 461 462void FragmentShader::deleteShader() 463{ 464 delete pixelShader; 465 pixelShader = nullptr; 466} 467 468} 469