mirror of
https://github.com/love2d/love.git
synced 2026-08-17 02:58:31 +02:00
Restructured some Shader code. Added runtime temporary caching and sharing of shader stages. Resolves issue #1235.
--HG-- branch : minor
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "window/Window.h"
|
||||
#include "Buffer.h"
|
||||
#include "Text.h"
|
||||
#include "ShaderStage.h"
|
||||
|
||||
#include "libraries/xxHash/xxhash.h"
|
||||
|
||||
@@ -126,9 +127,14 @@ love::graphics::Canvas *Graphics::newCanvas(const Canvas::Settings &settings)
|
||||
return new Canvas(settings);
|
||||
}
|
||||
|
||||
love::graphics::Shader *Graphics::newShader(const Shader::ShaderSource &source)
|
||||
love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles)
|
||||
{
|
||||
return new Shader(source);
|
||||
return new ShaderStage(this, stage, source, gles, cachekey);
|
||||
}
|
||||
|
||||
love::graphics::Shader *Graphics::newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
{
|
||||
return new Shader(vertex, pixel);
|
||||
}
|
||||
|
||||
love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags)
|
||||
@@ -281,7 +287,10 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
|
||||
try
|
||||
{
|
||||
if (!Shader::standardShaders[i])
|
||||
Shader::standardShaders[i] = newShader(defaultShaderCode[i][target][gammacorrect]);
|
||||
{
|
||||
const auto &code = defaultShaderCode[i][target][gammacorrect];
|
||||
Shader::standardShaders[i] = love::graphics::Graphics::newShader(code.source[ShaderStage::STAGE_VERTEX], code.source[ShaderStage::STAGE_PIXEL]);
|
||||
}
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
|
||||
@@ -68,7 +68,6 @@ public:
|
||||
love::graphics::ParticleSystem *newParticleSystem(Texture *texture, int size) override;
|
||||
|
||||
love::graphics::Canvas *newCanvas(const Canvas::Settings &settings) override;
|
||||
love::graphics::Shader *newShader(const Shader::ShaderSource &source) override;
|
||||
|
||||
love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override;
|
||||
|
||||
@@ -126,6 +125,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||
love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override;
|
||||
void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override;
|
||||
void initCapabilities() override;
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
Shader::Shader(const ShaderSource &source)
|
||||
: love::graphics::Shader(source)
|
||||
Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
: love::graphics::Shader(vertex, pixel)
|
||||
, program(0)
|
||||
, builtinUniforms()
|
||||
, builtinUniformInfo()
|
||||
@@ -73,71 +73,6 @@ Shader::~Shader()
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
|
||||
{
|
||||
GLenum glstage;
|
||||
const char *typestr;
|
||||
|
||||
if (!getConstant(stage, typestr))
|
||||
typestr = "";
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case STAGE_VERTEX:
|
||||
glstage = GL_VERTEX_SHADER;
|
||||
break;
|
||||
case STAGE_PIXEL:
|
||||
glstage = GL_FRAGMENT_SHADER;
|
||||
break;
|
||||
default:
|
||||
throw love::Exception("Cannot create shader object: unknown shader type.");
|
||||
break;
|
||||
}
|
||||
|
||||
GLuint shaderid = glCreateShader(glstage);
|
||||
|
||||
if (shaderid == 0)
|
||||
{
|
||||
if (glGetError() == GL_INVALID_ENUM)
|
||||
throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
|
||||
else
|
||||
throw love::Exception("Cannot create %s shader object.", typestr);
|
||||
}
|
||||
|
||||
const char *src = code.c_str();
|
||||
GLint srclen = (GLint) code.length();
|
||||
glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen);
|
||||
|
||||
glCompileShader(shaderid);
|
||||
|
||||
GLint infologlen;
|
||||
glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
|
||||
|
||||
// Get any warnings the shader compiler may have produced.
|
||||
if (infologlen > 0)
|
||||
{
|
||||
GLchar *infolog = new GLchar[infologlen];
|
||||
glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog);
|
||||
|
||||
// Save any warnings for later querying.
|
||||
shaderWarnings[stage] = infolog;
|
||||
|
||||
delete[] infolog;
|
||||
}
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
glDeleteShader(shaderid);
|
||||
throw love::Exception("Cannot compile %s shader code:\n%s",
|
||||
typestr, shaderWarnings[stage].c_str());
|
||||
}
|
||||
|
||||
return shaderid;
|
||||
}
|
||||
|
||||
void Shader::mapActiveUniforms()
|
||||
{
|
||||
// Built-in uniform locations default to -1 (nonexistent.)
|
||||
@@ -376,38 +311,22 @@ bool Shader::loadVolatile()
|
||||
textureUnits.clear();
|
||||
textureUnits.push_back(TextureUnit());
|
||||
|
||||
std::vector<GLuint> shaderids;
|
||||
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode();
|
||||
|
||||
// The shader program must have both vertex and pixel shader stages.
|
||||
const std::string &vertexcode = shaderSource.vertex.empty() ? defaults.vertex : shaderSource.vertex;
|
||||
const std::string &pixelcode = shaderSource.pixel.empty() ? defaults.pixel : shaderSource.pixel;
|
||||
|
||||
try
|
||||
for (const auto &stage : stages)
|
||||
{
|
||||
shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode));
|
||||
shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode));
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
for (GLuint id : shaderids)
|
||||
glDeleteShader(id);
|
||||
throw;
|
||||
if (stage.get() != nullptr)
|
||||
stage->loadVolatile();
|
||||
}
|
||||
|
||||
program = glCreateProgram();
|
||||
|
||||
if (program == 0)
|
||||
{
|
||||
for (GLuint id : shaderids)
|
||||
glDeleteShader(id);
|
||||
throw love::Exception("Cannot create shader program object.");
|
||||
}
|
||||
|
||||
for (GLuint id : shaderids)
|
||||
glAttachShader(program, id);
|
||||
for (const auto &stage : stages)
|
||||
{
|
||||
if (stage.get() != nullptr)
|
||||
glAttachShader(program, (GLuint) stage->getHandle());
|
||||
}
|
||||
|
||||
// Bind generic vertex attribute indices to names in the shader.
|
||||
for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
|
||||
@@ -419,10 +338,6 @@ bool Shader::loadVolatile()
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
// Flag shaders for auto-deletion when the program object is deleted.
|
||||
for (GLuint id : shaderids)
|
||||
glDeleteShader(id);
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
|
||||
@@ -477,8 +392,6 @@ void Shader::unloadVolatile()
|
||||
// And the locations of any built-in uniform variables.
|
||||
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
||||
builtinUniforms[i] = -1;
|
||||
|
||||
shaderWarnings.clear();
|
||||
}
|
||||
|
||||
std::string Shader::getProgramWarnings() const
|
||||
@@ -506,11 +419,15 @@ std::string Shader::getWarnings() const
|
||||
std::string warnings;
|
||||
const char *stagestr;
|
||||
|
||||
// Get the individual shader stage warnings
|
||||
for (const auto &warning : shaderWarnings)
|
||||
for (const auto &stage : stages)
|
||||
{
|
||||
if (getConstant(warning.first, stagestr))
|
||||
warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
|
||||
if (stage.get() == nullptr)
|
||||
continue;
|
||||
|
||||
const std::string &stagewarnings = stage->getWarnings();
|
||||
|
||||
if (ShaderStage::getConstant(stage->getStageType(), stagestr))
|
||||
warnings += std::string(stagestr) + std::string(" shader:\n") + stagewarnings;
|
||||
}
|
||||
|
||||
warnings += getProgramWarnings();
|
||||
|
||||
@@ -47,8 +47,7 @@ public:
|
||||
* Creates a new Shader using a list of source codes.
|
||||
* Source must contain either vertex or pixel shader code, or both.
|
||||
**/
|
||||
Shader(const ShaderSource &source);
|
||||
|
||||
Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel);
|
||||
virtual ~Shader();
|
||||
|
||||
// Implements Volatile
|
||||
@@ -96,16 +95,11 @@ private:
|
||||
TextureType getUniformTextureType(GLenum type) const;
|
||||
bool isDepthTextureType(GLenum type) const;
|
||||
|
||||
GLuint compileCode(ShaderStage stage, const std::string &code);
|
||||
|
||||
void flushStreamDraws() const;
|
||||
|
||||
// Get any warnings or errors generated only by the shader program object.
|
||||
std::string getProgramWarnings() const;
|
||||
|
||||
// Shader compiler warning strings for individual shader stages.
|
||||
std::map<ShaderStage, std::string> shaderWarnings;
|
||||
|
||||
// volatile
|
||||
GLuint program;
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "ShaderStage.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey)
|
||||
: love::graphics::ShaderStage(gfx, stage, source, gles, cachekey)
|
||||
, glShader(0)
|
||||
{
|
||||
loadVolatile();
|
||||
}
|
||||
|
||||
ShaderStage::~ShaderStage()
|
||||
{
|
||||
unloadVolatile();
|
||||
}
|
||||
|
||||
bool ShaderStage::loadVolatile()
|
||||
{
|
||||
if (glShader != 0)
|
||||
return true;
|
||||
|
||||
StageType stage = getStageType();
|
||||
const char *typestr = "unknown";
|
||||
getConstant(stage, typestr);
|
||||
|
||||
GLenum glstage = 0;
|
||||
if (stage == STAGE_VERTEX)
|
||||
glstage = GL_VERTEX_SHADER;
|
||||
else if (stage == STAGE_PIXEL)
|
||||
glstage = GL_FRAGMENT_SHADER;
|
||||
else
|
||||
throw love::Exception("%s shader stage is not handled in OpenGL backend code.", typestr);
|
||||
|
||||
glShader = glCreateShader(glstage);
|
||||
|
||||
if (glShader == 0)
|
||||
throw love::Exception("Cannot create OpenGL %s shader object.", typestr);
|
||||
|
||||
const std::string &sourcestring = getSource();
|
||||
const char *src = sourcestring.c_str();
|
||||
GLint srclen = (GLint) sourcestring.length();
|
||||
|
||||
glShaderSource(glShader, 1, (const GLchar **)&src, &srclen);
|
||||
glCompileShader(glShader);
|
||||
|
||||
GLint infologlen;
|
||||
glGetShaderiv(glShader, GL_INFO_LOG_LENGTH, &infologlen);
|
||||
|
||||
if (infologlen > 0)
|
||||
{
|
||||
GLchar *infolog = new GLchar[infologlen];
|
||||
glGetShaderInfoLog(glShader, infologlen, nullptr, infolog);
|
||||
|
||||
warnings = infolog;
|
||||
delete[] infolog;
|
||||
}
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
glGetShaderiv(glShader, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (glShader == GL_FALSE)
|
||||
{
|
||||
glDeleteShader(glShader);
|
||||
throw love::Exception("Cannot compile %s shader code:\n%s", typestr, warnings.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShaderStage::unloadVolatile()
|
||||
{
|
||||
if (glShader != 0)
|
||||
glDeleteShader(glShader);
|
||||
|
||||
glShader = 0;
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/ShaderStage.h"
|
||||
#include "graphics/Volatile.h"
|
||||
#include "OpenGL.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
class ShaderStage final : public love::graphics::ShaderStage
|
||||
{
|
||||
public:
|
||||
|
||||
ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey);
|
||||
virtual ~ShaderStage();
|
||||
|
||||
ptrdiff_t getHandle() const override { return glShader; }
|
||||
|
||||
// Implements Volatile.
|
||||
bool loadVolatile() override;
|
||||
void unloadVolatile() override;
|
||||
|
||||
private:
|
||||
|
||||
GLuint glShader;
|
||||
|
||||
}; // ShaderStage
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
Reference in New Issue
Block a user