#include "ShaderProgramCompiler.h" #include "GlRenderConstants.h" #include "GlScopedObjects.h" #include "GlShaderSources.h" #include #include namespace { void CopyErrorMessage(const std::string& message, int errorMessageSize, char* errorMessage) { if (!errorMessage || errorMessageSize <= 0) return; strncpy_s(errorMessage, errorMessageSize, message.c_str(), _TRUNCATE); } } ShaderProgramCompiler::ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, ShaderTextureBindings& textureBindings) : mRenderer(renderer), mRuntimeHost(runtimeHost), mTextureBindings(textureBindings) { } bool ShaderProgramCompiler::CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage) { std::string fragmentShaderSource; std::string loadError; if (!mRuntimeHost.BuildLayerFragmentShaderSource(state.layerId, fragmentShaderSource, loadError)) { CopyErrorMessage(loadError, errorMessageSize, errorMessage); return false; } return CompilePreparedLayerProgram(state, fragmentShaderSource, layerProgram, errorMessageSize, errorMessage); } bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::string& fragmentShaderSource, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage) { GLsizei errorBufferSize = 0; GLint compileResult = GL_FALSE; GLint linkResult = GL_FALSE; std::string loadError; std::vector textureBindings; const char* vertexSource = kFullscreenTriangleVertexShaderSource; const char* fragmentSource = fragmentShaderSource.c_str(); ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER)); glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL); glCompileShader(newVertexShader.get()); glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER)); glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL); glCompileShader(newFragmentShader.get()); glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlProgram newProgram(glCreateProgram()); glAttachShader(newProgram.get(), newVertexShader.get()); glAttachShader(newProgram.get(), newFragmentShader.get()); glLinkProgram(newProgram.get()); glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult); if (linkResult == GL_FALSE) { glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } for (const ShaderTextureAsset& textureAsset : state.textureAssets) { LayerProgram::TextureBinding textureBinding; textureBinding.samplerName = textureAsset.id; textureBinding.sourcePath = textureAsset.path; if (!mTextureBindings.LoadTextureAsset(textureAsset, textureBinding.texture, loadError)) { for (LayerProgram::TextureBinding& loadedTexture : textureBindings) { if (loadedTexture.texture != 0) glDeleteTextures(1, &loadedTexture.texture); } CopyErrorMessage(loadError, errorMessageSize, errorMessage); return false; } textureBindings.push_back(textureBinding); } std::vector textBindings; mTextureBindings.CreateTextBindings(state, textBindings); layerProgram.layerId = state.layerId; layerProgram.shaderId = state.shaderId; layerProgram.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames()); layerProgram.textureBindings.swap(textureBindings); layerProgram.textBindings.swap(textBindings); const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams"); if (globalParamsIndex != GL_INVALID_INDEX) glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint); const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames(); glUseProgram(newProgram.get()); mTextureBindings.AssignLayerSamplerUniforms(newProgram.get(), state, layerProgram, historyCap); glUseProgram(0); layerProgram.program = newProgram.release(); layerProgram.vertexShader = newVertexShader.release(); layerProgram.fragmentShader = newFragmentShader.release(); return true; } bool ShaderProgramCompiler::CompileDecodeShader(int errorMessageSize, char* errorMessage) { GLsizei errorBufferSize = 0; GLint compileResult = GL_FALSE; GLint linkResult = GL_FALSE; const char* vertexSource = kFullscreenTriangleVertexShaderSource; const char* fragmentSource = kDecodeFragmentShaderSource; ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER)); glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL); glCompileShader(newVertexShader.get()); glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER)); glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL); glCompileShader(newFragmentShader.get()); glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlProgram newProgram(glCreateProgram()); glAttachShader(newProgram.get(), newVertexShader.get()); glAttachShader(newProgram.get(), newFragmentShader.get()); glLinkProgram(newProgram.get()); glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult); if (linkResult == GL_FALSE) { glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } mRenderer.DestroyDecodeShaderProgram(); mRenderer.SetDecodeShaderProgram(newProgram.release(), newVertexShader.release(), newFragmentShader.release()); return true; } bool ShaderProgramCompiler::CompileOutputPackShader(int errorMessageSize, char* errorMessage) { GLsizei errorBufferSize = 0; GLint compileResult = GL_FALSE; GLint linkResult = GL_FALSE; const char* vertexSource = kFullscreenTriangleVertexShaderSource; const char* fragmentSource = kOutputPackFragmentShaderSource; ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER)); glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL); glCompileShader(newVertexShader.get()); glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER)); glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL); glCompileShader(newFragmentShader.get()); glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult); if (compileResult == GL_FALSE) { glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } ScopedGlProgram newProgram(glCreateProgram()); glAttachShader(newProgram.get(), newVertexShader.get()); glAttachShader(newProgram.get(), newFragmentShader.get()); glLinkProgram(newProgram.get()); glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult); if (linkResult == GL_FALSE) { glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage); return false; } glUseProgram(newProgram.get()); const GLint outputSamplerLocation = glGetUniformLocation(newProgram.get(), "uOutputRgb"); if (outputSamplerLocation >= 0) glUniform1i(outputSamplerLocation, 0); glUseProgram(0); mRenderer.DestroyOutputPackShaderProgram(); mRenderer.SetOutputPackShaderProgram(newProgram.release(), newVertexShader.release(), newFragmentShader.release()); return true; }